Skip to content

Commit d1a31df

Browse files
committed
Apply eviction to caching-defined Regions using @EnableEviction annotation configuration.
Resolves spring-projectsgh-519.
1 parent 0d899b8 commit d1a31df

File tree

3 files changed

+195
-63
lines changed

3 files changed

+195
-63
lines changed

Diff for: spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEviction.java

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
* limitations under the License.
1515
*
1616
*/
17-
1817
package org.springframework.data.gemfire.config.annotation;
1918

2019
import java.lang.annotation.Documented;

Diff for: spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EvictionConfiguration.java

+142-56
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717
package org.springframework.data.gemfire.config.annotation;
1818

1919
import static org.springframework.data.gemfire.config.annotation.EnableEviction.EvictionPolicy;
20-
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
21-
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
22-
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
2320
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
2421

2522
import java.lang.annotation.Annotation;
@@ -30,8 +27,10 @@
3027
import java.util.Set;
3128
import java.util.function.Supplier;
3229

30+
import org.apache.geode.cache.AttributesMutator;
3331
import org.apache.geode.cache.EvictionAttributes;
3432
import org.apache.geode.cache.Region;
33+
import org.apache.geode.cache.RegionAttributes;
3534
import org.apache.geode.cache.util.ObjectSizer;
3635

3736
import org.springframework.beans.BeansException;
@@ -41,6 +40,8 @@
4140
import org.springframework.context.annotation.Bean;
4241
import org.springframework.context.annotation.Configuration;
4342
import org.springframework.context.annotation.ImportAware;
43+
import org.springframework.context.event.ContextRefreshedEvent;
44+
import org.springframework.context.event.EventListener;
4445
import org.springframework.core.annotation.AnnotationAttributes;
4546
import org.springframework.core.type.AnnotationMetadata;
4647
import org.springframework.data.gemfire.PeerRegionFactoryBean;
@@ -51,7 +52,10 @@
5152
import org.springframework.data.gemfire.eviction.EvictionActionType;
5253
import org.springframework.data.gemfire.eviction.EvictionAttributesFactoryBean;
5354
import org.springframework.data.gemfire.eviction.EvictionPolicyType;
55+
import org.springframework.data.gemfire.util.ArrayUtils;
56+
import org.springframework.data.gemfire.util.CollectionUtils;
5457
import org.springframework.lang.NonNull;
58+
import org.springframework.lang.Nullable;
5559
import org.springframework.util.Assert;
5660
import org.springframework.util.StringUtils;
5761

@@ -60,22 +64,22 @@
6064
* Eviction policy configuration on cache {@link Region Regions}.
6165
*
6266
* @author John Blum
67+
* @see org.apache.geode.cache.EvictionAttributes
68+
* @see org.apache.geode.cache.Region
69+
* @see org.apache.geode.cache.util.ObjectSizer
6370
* @see org.springframework.beans.factory.config.BeanPostProcessor
6471
* @see org.springframework.context.ApplicationContext
6572
* @see org.springframework.context.ApplicationContextAware
6673
* @see org.springframework.context.annotation.Bean
6774
* @see org.springframework.context.annotation.Configuration
6875
* @see org.springframework.context.annotation.ImportAware
69-
* @see PeerRegionFactoryBean
76+
* @see org.springframework.data.gemfire.PeerRegionFactoryBean
7077
* @see org.springframework.data.gemfire.ResolvableRegionFactoryBean
7178
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
7279
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
7380
* @see org.springframework.data.gemfire.eviction.EvictionActionType
7481
* @see org.springframework.data.gemfire.eviction.EvictionAttributesFactoryBean
7582
* @see org.springframework.data.gemfire.eviction.EvictionPolicyType
76-
* @see org.apache.geode.cache.EvictionAttributes
77-
* @see org.apache.geode.cache.Region
78-
* @see org.apache.geode.cache.util.ObjectSizer
7983
* @since 1.9.0
8084
*/
8185
@Configuration
@@ -94,7 +98,7 @@ public class EvictionConfiguration extends AbstractAnnotationConfigSupport
9498
* @see java.lang.Class
9599
*/
96100
@Override
97-
protected Class<? extends Annotation> getAnnotationType() {
101+
protected @NonNull Class<? extends Annotation> getAnnotationType() {
98102
return EnableEviction.class;
99103
}
100104

@@ -115,15 +119,17 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
115119
* @inheritDoc
116120
*/
117121
@Override
118-
public void setImportMetadata(AnnotationMetadata importMetadata) {
122+
public void setImportMetadata(@NonNull AnnotationMetadata importMetadata) {
119123

120124
if (isAnnotationPresent(importMetadata)) {
121125

122126
AnnotationAttributes enableEvictionAttributes = getAnnotationAttributes(importMetadata);
123127

124128
AnnotationAttributes[] policies = enableEvictionAttributes.getAnnotationArray("policies");
125129

126-
for (AnnotationAttributes evictionPolicyAttributes : nullSafeArray(policies, AnnotationAttributes.class)) {
130+
for (AnnotationAttributes evictionPolicyAttributes :
131+
ArrayUtils.nullSafeArray(policies, AnnotationAttributes.class)) {
132+
127133
this.evictionPolicyConfigurer =
128134
ComposableEvictionPolicyConfigurer.compose(this.evictionPolicyConfigurer,
129135
EvictionPolicyMetaData.from(evictionPolicyAttributes, this.applicationContext));
@@ -173,23 +179,47 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
173179
};
174180
}
175181

182+
@SuppressWarnings("unused")
183+
@EventListener(ContextRefreshedEvent.class)
184+
public void evictionContextRefreshedListener(@NonNull ContextRefreshedEvent event) {
185+
186+
ApplicationContext applicationContext = event.getApplicationContext();
187+
188+
for (Region<?, ?> region : applicationContext.getBeansOfType(Region.class).values()) {
189+
getEvictionPolicyConfigurer().configure(region);
190+
}
191+
}
192+
176193
/**
177-
* {@link EvictionPolicyConfigurer} configures the Eviction policy of a GemFire {@link Region}.
194+
* {@link EvictionPolicyConfigurer} configures the Eviction policy of an Apache Geode {@link Region}.
195+
*
196+
* @see java.lang.FunctionalInterface
178197
*/
198+
@FunctionalInterface
179199
protected interface EvictionPolicyConfigurer {
180200

181201
/**
182-
* Configure the Eviction policy on the given SDG {@link PeerRegionFactoryBean} or {@link ClientRegionFactoryBean}
183-
* used to create a GemFire {@link Region}.
202+
* Configure the Eviction policy on the given SDG {@link ClientRegionFactoryBean}
203+
* or {@link PeerRegionFactoryBean} used to create an Apache Geode {@link Region}.
184204
*
185-
* @param regionFactoryBean {@link PeerRegionFactoryBean} or {@link ClientRegionFactoryBean} used to create
186-
* a GemFire {@link Region}.
205+
* @param regionBean {@link ClientRegionFactoryBean} or {@link PeerRegionFactoryBean} used to create
206+
* an Apache Geode {@link Region}.
187207
* @return the given {@code regionFactoryBean}.
188-
* @see PeerRegionFactoryBean
208+
* @see org.springframework.data.gemfire.PeerRegionFactoryBean
189209
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
190210
*/
191-
Object configure(Object regionFactoryBean);
211+
Object configure(Object regionBean);
192212

213+
/**
214+
* Configures the Eviction policy of the given Apache Geode {@link Region}.
215+
*
216+
* @param region {@link Region} on which to configure the Eviction policy.
217+
* @return the given {@link Region}.
218+
* @see org.apache.geode.cache.Region
219+
*/
220+
default Region<?, ?> configure(Region<?, ?> region) {
221+
return region;
222+
}
193223
}
194224

195225
/**
@@ -201,9 +231,6 @@ protected interface EvictionPolicyConfigurer {
201231
*/
202232
protected static class ComposableEvictionPolicyConfigurer implements EvictionPolicyConfigurer {
203233

204-
private final EvictionPolicyConfigurer one;
205-
private final EvictionPolicyConfigurer two;
206-
207234
/**
208235
* Composes the array of {@link EvictionPolicyConfigurer} objects into a single
209236
* {@link EvictionPolicyConfigurer} implementation using the Composite Software Design Pattern.
@@ -215,8 +242,8 @@ protected static class ComposableEvictionPolicyConfigurer implements EvictionPol
215242
* @see #compose(Iterable)
216243
*/
217244
@SuppressWarnings("unused")
218-
protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer[] array) {
219-
return compose(Arrays.asList(nullSafeArray(array, EvictionPolicyConfigurer.class)));
245+
protected static @Nullable EvictionPolicyConfigurer compose(EvictionPolicyConfigurer[] array) {
246+
return compose(Arrays.asList(ArrayUtils.nullSafeArray(array, EvictionPolicyConfigurer.class)));
220247
}
221248

222249
/**
@@ -229,11 +256,11 @@ protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer[] arr
229256
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
230257
* @see #compose(EvictionPolicyConfigurer, EvictionPolicyConfigurer)
231258
*/
232-
protected static EvictionPolicyConfigurer compose(Iterable<EvictionPolicyConfigurer> iterable) {
259+
protected static @Nullable EvictionPolicyConfigurer compose(Iterable<EvictionPolicyConfigurer> iterable) {
233260

234261
EvictionPolicyConfigurer current = null;
235262

236-
for (EvictionPolicyConfigurer evictionPolicyConfigurer : nullSafeIterable(iterable)) {
263+
for (EvictionPolicyConfigurer evictionPolicyConfigurer : CollectionUtils.nullSafeIterable(iterable)) {
237264
current = compose(current, evictionPolicyConfigurer);
238265
}
239266

@@ -249,13 +276,17 @@ protected static EvictionPolicyConfigurer compose(Iterable<EvictionPolicyConfigu
249276
* @return an {@link EvictionPolicyConfigurer} object implementation composed of
250277
* multiple {@link EvictionPolicyConfigurer} objects using the Composite Software Design Pattern.
251278
*/
252-
protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer one, EvictionPolicyConfigurer two) {
279+
protected static @Nullable EvictionPolicyConfigurer compose(@Nullable EvictionPolicyConfigurer one,
280+
@Nullable EvictionPolicyConfigurer two) {
253281

254282
return one == null ? two
255-
: (two == null ? one
256-
: new ComposableEvictionPolicyConfigurer(one, two));
283+
: two == null ? one
284+
: new ComposableEvictionPolicyConfigurer(one, two);
257285
}
258286

287+
private final EvictionPolicyConfigurer one;
288+
private final EvictionPolicyConfigurer two;
289+
259290
/**
260291
* Constructs a new instance of the {@link ComposableEvictionPolicyConfigurer} initialized with the two
261292
* {@link EvictionPolicyConfigurer} objects.
@@ -273,19 +304,24 @@ private ComposableEvictionPolicyConfigurer(EvictionPolicyConfigurer one, Evictio
273304
* @inheritDoc
274305
*/
275306
@Override
276-
public Object configure(Object regionFactoryBean) {
277-
return this.two.configure(this.one.configure(regionFactoryBean));
307+
public Object configure(Object regionBean) {
308+
return this.two.configure(this.one.configure(regionBean));
309+
}
310+
311+
/**
312+
* @inheritDoc
313+
*/
314+
@Override
315+
public Region<?, ?> configure(Region<?, ?> region) {
316+
return this.two.configure(this.one.configure(region));
278317
}
279318
}
280319

320+
@SuppressWarnings("unused")
281321
protected static class EvictionPolicyMetaData implements EvictionPolicyConfigurer {
282322

283323
protected static final String[] ALL_REGIONS = new String[0];
284324

285-
private final EvictionAttributes evictionAttributes;
286-
287-
private final Set<String> regionNames = new HashSet<>();
288-
289325
protected static EvictionPolicyMetaData from(@NonNull AnnotationAttributes evictionPolicyAttributes,
290326
@NonNull ApplicationContext applicationContext) {
291327

@@ -347,6 +383,10 @@ protected static Integer resolveThreshold(int maximum, EvictionPolicyType type)
347383
return EvictionPolicyType.HEAP_PERCENTAGE.equals(type) ? null : maximum;
348384
}
349385

386+
private final EvictionAttributes evictionAttributes;
387+
388+
private final Set<String> regionNames = new HashSet<>();
389+
350390
/**
351391
* Constructs an instance of {@link EvictionPolicyMetaData} initialized with the given
352392
* {@link EvictionAttributes} applying to all {@link Region Regions}.
@@ -371,25 +411,11 @@ protected EvictionPolicyMetaData(EvictionAttributes evictionAttributes) {
371411
*/
372412
protected EvictionPolicyMetaData(EvictionAttributes evictionAttributes, String[] regionNames) {
373413

374-
this.evictionAttributes = Optional.ofNullable(evictionAttributes).orElseThrow(() ->
375-
newIllegalArgumentException("EvictionAttributes are required"));
376-
377-
Collections.addAll(this.regionNames, nullSafeArray(regionNames, String.class));
378-
}
414+
Assert.notNull(evictionAttributes, "EvictionAttributes must not be null");
379415

380-
/**
381-
* Returns an instance of the {@link EvictionAttributes} specifying the Eviction policy configuration
382-
* captured in this Eviction policy meta-data.
383-
*
384-
* @return an instance of the {@link EvictionAttributes} specifying the {@link Region}
385-
* Eviction policy configuration.
386-
* @throws IllegalStateException if the {@link EvictionAttributes} were not properly initialized.
387-
* @see org.apache.geode.cache.EvictionAttributes
388-
*/
389-
protected EvictionAttributes getEvictionAttributes() {
416+
this.evictionAttributes = evictionAttributes;
390417

391-
return Optional.ofNullable(this.evictionAttributes).orElseThrow(() ->
392-
newIllegalStateException("EvictionAttributes was not properly configured and initialized"));
418+
Collections.addAll(this.regionNames, ArrayUtils.nullSafeArray(regionNames, String.class));
393419
}
394420

395421
/**
@@ -401,10 +427,23 @@ protected EvictionAttributes getEvictionAttributes() {
401427
* @see #resolveRegionName(Object)
402428
* @see #accepts(Supplier)
403429
*/
404-
protected boolean accepts(Object regionFactoryBean) {
430+
protected boolean accepts(@Nullable Object regionFactoryBean) {
405431
return isRegionFactoryBean(regionFactoryBean) && accepts(() -> resolveRegionName(regionFactoryBean));
406432
}
407433

434+
/**
435+
* Determines whether the given {@link Region} is accepted for Eviction policy configuration.
436+
*
437+
* @param region {@link Region} evaluated for Eviction policy configuration.
438+
* @return a boolean value indicating whether the given {@link Region} is accepted for
439+
* Eviction policy configuration.
440+
* @see org.apache.geode.cache.Region
441+
* @see #accepts(Supplier)
442+
*/
443+
protected boolean accepts(@Nullable Region<?, ?> region) {
444+
return region != null && accepts(() -> region.getName());
445+
}
446+
408447
/**
409448
* Determine whether the {@link Region} identified by name is accepted for Eviction policy configuration.
410449
*
@@ -425,7 +464,7 @@ protected boolean accepts(Supplier<String> regionName) {
425464
protected String resolveRegionName(Object regionFactoryBean) {
426465

427466
return regionFactoryBean instanceof ResolvableRegionFactoryBean
428-
? ((ResolvableRegionFactoryBean) regionFactoryBean).resolveRegionName()
467+
? ((ResolvableRegionFactoryBean<?, ?>) regionFactoryBean).resolveRegionName()
429468
: null;
430469
}
431470

@@ -447,12 +486,59 @@ protected EvictingRegionFactoryBean setEvictionAttributes(EvictingRegionFactoryB
447486
return regionFactoryBean;
448487
}
449488

489+
/**
490+
* Returns an instance of the {@link EvictionAttributes} specifying the Eviction policy configuration
491+
* captured in this Eviction policy meta-data.
492+
*
493+
* @return an instance of the {@link EvictionAttributes} specifying the {@link Region}
494+
* Eviction policy configuration.
495+
* @throws IllegalStateException if the {@link EvictionAttributes} were not properly initialized.
496+
* @see org.apache.geode.cache.EvictionAttributes
497+
*/
498+
protected EvictionAttributes getEvictionAttributes() {
499+
500+
return Optional.ofNullable(this.evictionAttributes).orElseThrow(() ->
501+
newIllegalStateException("EvictionAttributes was not properly configured and initialized"));
502+
}
503+
504+
/**
505+
* @inheritDoc
506+
*/
450507
@Override
451-
public Object configure(Object regionFactoryBean) {
508+
public Object configure(Object regionBean) {
509+
510+
return accepts(regionBean)
511+
? setEvictionAttributes((EvictingRegionFactoryBean) regionBean)
512+
: regionBean;
513+
}
514+
515+
/**
516+
* @inheritDoc
517+
*/
518+
@Override
519+
public Region<?, ?> configure(Region<?, ?> region) {
520+
521+
Optional.ofNullable(region)
522+
.filter(this::accepts)
523+
.filter(this::isDefaultEvictionEntryMaximum)
524+
.map(Region::getAttributesMutator)
525+
.map(AttributesMutator::getEvictionAttributesMutator)
526+
.ifPresent(evictionAttributesMutator ->
527+
evictionAttributesMutator.setMaximum(getEvictionAttributes().getMaximum()));
528+
529+
return region;
530+
}
531+
532+
private boolean isDefaultEvictionEntryMaximum(Region<?, ?> region) {
533+
return region != null && isDefaultEvictionEntryMaximum(region.getAttributes());
534+
}
535+
536+
private boolean isDefaultEvictionEntryMaximum(RegionAttributes<?, ?> regionAttributes) {
537+
return regionAttributes != null && isDefaultEvictionEntryMaximum(regionAttributes.getEvictionAttributes());
538+
}
452539

453-
return accepts(regionFactoryBean)
454-
? setEvictionAttributes((EvictingRegionFactoryBean) regionFactoryBean)
455-
: regionFactoryBean;
540+
private boolean isDefaultEvictionEntryMaximum(EvictionAttributes evictionAttributes) {
541+
return EvictionAttributes.DEFAULT_ENTRIES_MAXIMUM == evictionAttributes.getMaximum();
456542
}
457543
}
458544
}

0 commit comments

Comments
 (0)