DATAGEODE-281 - Introduce a PoolResolver strategy interface to resolve Pool instances and provide a layer of indirection between SDG and Apache Geode's static PoolManager class.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 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.client;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PoolResolver} is a strategy interface for resolving references to Apache Geode {@link Pool} instances.
|
||||
*
|
||||
* This is used throughout SDG's codebase to separate SDG's {@link Pool} resolution logic from being explicitly tied to
|
||||
* to Apache Geode's static {@link org.apache.geode.cache.client.PoolManager} class. This interfaces also serves
|
||||
* as an SPI for different strategies when resolving a {@link Pool}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.FunctionalInterface
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PoolResolver {
|
||||
|
||||
/**
|
||||
* Resolves the {@link Pool} instance used by the given {@link Region}.
|
||||
*
|
||||
* If the {@link Region} is a {@literal client} {@link Region} but does not explicitly configure
|
||||
* a specific {@link Pool} reference, then the {@literal DEFAULT} {@link Pool} is returned.
|
||||
*
|
||||
* If the {@link Region} is {@literal local} or a {@literal peer} {@link Region}, then {@literal null}
|
||||
* is returned.
|
||||
*
|
||||
* @param region {@link Region} from which to resolve the associated {@link Pool}.
|
||||
* @return the {@link Pool} instance associated with the given {@link Region},
|
||||
* or the {@literal DEFAULT} {@link Pool} if the {@link Region} is a {@literal client} {@link Region},
|
||||
* or {@literal null} if the {@link Region} is not a {@literal client} {@link Region}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
*/
|
||||
default @Nullable Pool resolve(@Nullable Region<?, ?> region) {
|
||||
|
||||
return Optional.ofNullable(region)
|
||||
.map(Region::getAttributes)
|
||||
.map(RegionAttributes::getPoolName)
|
||||
.filter(StringUtils::hasText)
|
||||
.map(this::resolve)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a {@link Pool} with the given {@link String name}.
|
||||
*
|
||||
* @param poolName {@link String name} of the {@link Pool} to resolve.
|
||||
* @return the {@link Pool} with the given {@link String name} or {@link null} if no {@link Pool} exists with
|
||||
* the {@link String name}.
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
*/
|
||||
@Nullable Pool resolve(@Nullable String poolName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 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.client.support;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.cache.client.PoolManager;
|
||||
|
||||
import org.springframework.data.gemfire.client.PoolResolver;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PoolManagerPoolResolver} is an implementation of {@link PoolResolver} that delegates all {@link Pool}
|
||||
* resolution logic to the Apache Geode {@link PoolManager}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.cache.client.PoolManager
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class PoolManagerPoolResolver implements PoolResolver {
|
||||
|
||||
/**
|
||||
* Resolves the {@link Pool} used by the given {@link Region} by delegating to {@link PoolManager#find(Region)}.
|
||||
*
|
||||
* @param region {@link Region} from which to resolve the associated {@link Pool}.
|
||||
* @return the {@link Pool} used by the given {@link Region}.
|
||||
* @see org.apache.geode.cache.client.PoolManager#find(Region)
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Pool resolve(@Nullable Region<?, ?> region) {
|
||||
return region != null ? PoolManager.find(region) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the {@link Pool} with the given {@link String name} by delegating to {@link PoolManager#find(String)}.
|
||||
*
|
||||
* @param poolName {@link String name} of the {@link Pool} to resolve.
|
||||
* @return the {@link Pool} with the given {@link String name} or {@link null} if no {@link Pool} exists with
|
||||
* the {@link String name}.
|
||||
* @see org.apache.geode.cache.client.PoolManager#find(String)
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Pool resolve(@Nullable String poolName) {
|
||||
return StringUtils.hasText(poolName) ? PoolManager.find(poolName) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 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.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link PoolResolver}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PoolResolverUnitTests {
|
||||
|
||||
@Mock
|
||||
private TestPoolResolver testPoolResolver;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(this.testPoolResolver.resolve(any(Region.class))).thenCallRealMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromRegionWithPoolReturnsPool() {
|
||||
|
||||
Pool mockPool = mock(Pool.class);
|
||||
|
||||
Region mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn("TestPool");
|
||||
when(this.testPoolResolver.resolve(eq("TestPool"))).thenReturn(mockPool);
|
||||
|
||||
assertThat(this.testPoolResolver.resolve(mockRegion)).isEqualTo(mockPool);
|
||||
|
||||
verifyNoInteractions(mockPool);
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
verify(this.testPoolResolver, times(1)).resolve(eq("TestPool"));
|
||||
}
|
||||
|
||||
private void testResolvePoolFromRegionWithNoPoolReturnsNull(String poolName) {
|
||||
|
||||
Region mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn(poolName);
|
||||
|
||||
assertThat(this.testPoolResolver.resolve(mockRegion)).isNull();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getPoolName();
|
||||
verify(this.testPoolResolver, never()).resolve(eq(poolName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolWithRegionWithBlankPoolNameReturnsNull() {
|
||||
testResolvePoolFromRegionWithNoPoolReturnsNull(" ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolWithRegionWithEmptyPoolNameReturnsNull() {
|
||||
testResolvePoolFromRegionWithNoPoolReturnsNull("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolWithRegionWithNullPoolNameReturnsNull() {
|
||||
testResolvePoolFromRegionWithNoPoolReturnsNull(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolWithNullRegionIsNullSafeAndReturnsNull() {
|
||||
assertThat(this.testPoolResolver.resolve((Region) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolWithRegionHavingNullRegionAttributesIsNullSafeAndReturnsNull() {
|
||||
|
||||
Region mockRegion = mock(Region.class);
|
||||
|
||||
assertThat(this.testPoolResolver.resolve(mockRegion)).isNull();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
}
|
||||
|
||||
private static abstract class TestPoolResolver implements PoolResolver { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 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.client.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.PoolResolver;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
|
||||
import org.springframework.data.gemfire.config.annotation.EnablePool;
|
||||
import org.springframework.data.gemfire.config.annotation.EnablePools;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration Tests for {@link PoolManagerPoolResolver}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.cache.client.PoolManager
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @see org.springframework.data.gemfire.client.support.PoolManagerPoolResolver
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings("unused")
|
||||
public class PoolManagerPoolResolverIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private ClientCache clientCache;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("CarPool")
|
||||
private Pool carPool;
|
||||
|
||||
private Pool defaultPool;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("SwimmingPool")
|
||||
private Pool swimmingPool;
|
||||
|
||||
private PoolResolver poolResolver = new PoolManagerPoolResolver();
|
||||
|
||||
@Resource(name = "RegionWithDefaultPool")
|
||||
private Region<?, ?> regionWithDefaultPool;
|
||||
|
||||
@Resource(name = "RegionWithSwimmingPool")
|
||||
private Region<?, ?> regionWithSwimmingPool;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
assertThat(this.clientCache).isNotNull();
|
||||
assertThat(this.clientCache.getName()).isEqualTo(PoolManagerPoolResolverIntegrationTests.class.getSimpleName());
|
||||
assertThat(this.carPool).isNotNull();
|
||||
assertThat(this.carPool.getName()).isEqualTo("CarPool");
|
||||
assertThat(this.swimmingPool).isNotNull();
|
||||
assertThat(this.swimmingPool.getName()).isEqualTo("SwimmingPool");
|
||||
|
||||
this.defaultPool = this.clientCache.getDefaultPool();
|
||||
|
||||
assertThat(this.defaultPool).isNotNull();
|
||||
assertThat(this.defaultPool).isNotSameAs(this.carPool);
|
||||
assertThat(this.defaultPool).isNotSameAs(this.swimmingPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromName() {
|
||||
|
||||
assertThat(this.poolResolver.resolve("DEFAULT")).isEqualTo(this.defaultPool);
|
||||
assertThat(this.poolResolver.resolve("CarPool")).isEqualTo(this.carPool);
|
||||
assertThat(this.poolResolver.resolve("SwimmingPool")).isEqualTo(this.swimmingPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromBlankPoolNameReturnsNull() {
|
||||
assertThat(this.poolResolver.resolve(" ")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromEmptyPoolNameReturnsNull() {
|
||||
assertThat(this.poolResolver.resolve("")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromNullPoolNameReturnsNull() {
|
||||
assertThat(this.poolResolver.resolve((String) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromRegion() {
|
||||
|
||||
assertThat(this.poolResolver.resolve(this.regionWithDefaultPool)).isEqualTo(this.defaultPool);
|
||||
assertThat(this.poolResolver.resolve(this.regionWithSwimmingPool)).isEqualTo(this.swimmingPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePoolFromNullRegionIsNullSafeAndReturnsNull() {
|
||||
assertThat(this.poolResolver.resolve((Region) null)).isNull();
|
||||
}
|
||||
|
||||
@ClientCacheApplication(name = "PoolManagerPoolResolverIntegrationTests")
|
||||
@EnablePools(pools = {
|
||||
@EnablePool(name = "DEFAULT", servers = @EnablePool.Server),
|
||||
@EnablePool(name = "CarPool", locators = @EnablePool.Locator),
|
||||
@EnablePool(name = "SwimmingPool", locators = @EnablePool.Locator)
|
||||
})
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean("RegionWithDefaultPool")
|
||||
ClientRegionFactoryBean regionWithDefaultPool(ClientCache clientCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> clientRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
clientRegion.setCache(clientCache);
|
||||
clientRegion.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return clientRegion;
|
||||
}
|
||||
|
||||
@Bean("RegionWithSwimmingPool")
|
||||
@DependsOn("SwimmingPool")
|
||||
ClientRegionFactoryBean regionWithNamedPool(ClientCache clientCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> clientRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
clientRegion.setCache(clientCache);
|
||||
clientRegion.setPoolName("SwimmingPool");
|
||||
clientRegion.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return clientRegion;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user