DATAGEODE-314 - Introduce new BeanFactoryPoolResolver implementation.

The BeanFactoryPoolResolver implementation resolves a managed, named Pool object (bean) from the Spring BeanFactory (container).
This commit is contained in:
John Blum
2020-03-24 14:26:12 -07:00
parent 735c9f8ea4
commit 65ddad967d
2 changed files with 281 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2020 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.client.Pool;
import org.apache.shiro.util.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.data.gemfire.client.PoolResolver;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link PoolResolver} implementation that uses the Spring {@link BeanFactory} to resolve managed {@link Pool} objects.
* This means the {@link Pool} was configured and initialized by the Spring container given the {@link Pool} would be a
* proper bean declaration in this case.
*
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.data.gemfire.client.PoolResolver
* @since 2.3.0
*/
public class BeanFactoryPoolResolver implements BeanFactoryAware, PoolResolver {
private BeanFactory beanFactory;
/**
* Constructs a new instance of the {@link BeanFactoryPoolResolver} initialized with
* the given Spring {@link BeanFactory} used to resolve managed {@link Pool} objects.
*
* @param beanFactory Spring {@link BeanFactory} used to resolve managed {@link Pool} objects.
* @see org.springframework.beans.factory.BeanFactory
*/
public BeanFactoryPoolResolver(@NonNull BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
/**
* @inheritDoc
*/
@Override
public final void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the configured Spring {@link BeanFactory} used to resolve managed {@link Pool} objects.
*
* @return a reference to the configured Spring {@link BeanFactory}.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
/**
* Resolves the managed, {@link String named} Apache Geode {@link Pool} from the Spring {@link BeanFactory}.
*
* @param poolName {@link String name} of the {@link Pool} to resolve.
* @return the resolved, {@link String named}, managed {@link Pool} object or {@literal null} if no {@link Pool}
* with the given {@link String name} could be resolved from the configured Spring {@link BeanFactory}.
* @see org.apache.geode.cache.client.Pool
* @see #getBeanFactory()
*/
@Nullable @Override
public Pool resolve(@Nullable String poolName) {
BeanFactory beanFactory = getBeanFactory();
return StringUtils.hasText(poolName) && beanFactory.containsBean(poolName)
? beanFactory.getBean(poolName, Pool.class)
: null;
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright 2020 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 static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
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.verifyZeroInteractions;
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.client.Pool;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
/**
* Unit Tests for {@link BeanFactoryPoolResolver}.
*
* @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.client.Pool
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.data.gemfire.client.support.BeanFactoryPoolResolver
* @since 2.3.0
*/
@RunWith(MockitoJUnitRunner.class)
public class BeanFactoryPoolResolverUnitTests {
@Mock
private BeanFactory mockBeanFactory;
private BeanFactoryPoolResolver poolResolver;
@Mock
private Pool mockPool;
@Before
public void setup() {
this.poolResolver = new BeanFactoryPoolResolver(this.mockBeanFactory);
}
@Test
public void constructBeanFactoryPoolResolverWithBeanFactory() {
BeanFactoryPoolResolver poolResolver = new BeanFactoryPoolResolver(this.mockBeanFactory);
assertThat(poolResolver).isNotNull();
assertThat(poolResolver.getBeanFactory()).isEqualTo(this.mockBeanFactory);
}
@SuppressWarnings("all")
@Test(expected = IllegalArgumentException.class)
public void constructBeanFactoryPoolResolverWithNullThrowsIllegalArgumentException() {
try {
new BeanFactoryPoolResolver(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("BeanFactory must not be null");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void setAndGetBeanFactory() {
BeanFactory mockBeanFactoryTwo = mock(BeanFactory.class);
assertThat(this.poolResolver.getBeanFactory()).isEqualTo(this.mockBeanFactory);
this.poolResolver.setBeanFactory(mockBeanFactoryTwo);
assertThat(this.poolResolver.getBeanFactory()).isEqualTo(mockBeanFactoryTwo);
}
@SuppressWarnings("all")
@Test(expected = IllegalArgumentException.class)
public void setBeanFactoryToNullThrowsIllegalArgumentException() {
try {
assertThat(this.poolResolver.getBeanFactory()).isEqualTo(this.mockBeanFactory);
this.poolResolver.setBeanFactory(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("BeanFactory must not be null");
assertThat(expected).hasNoCause();
throw expected;
}
finally {
assertThat(this.poolResolver.getBeanFactory()).isEqualTo(this.mockBeanFactory);
}
}
@Test
public void resolveResolvablePoolByName() {
when(this.mockBeanFactory.containsBean(eq("TestPool"))).thenReturn(true);
when(this.mockBeanFactory.getBean(eq("TestPool"), eq(Pool.class))).thenReturn(this.mockPool);
assertThat(this.poolResolver.resolve("TestPool")).isEqualTo(this.mockPool);
verify(this.mockBeanFactory, times(1)).containsBean(eq("TestPool"));
verify(this.mockBeanFactory, times(1)).getBean(eq("TestPool"), eq(Pool.class));
verifyZeroInteractions(this.mockPool);
}
private Pool testResolveUnresolvablePoolByInvalidName(String poolName) {
try {
return this.poolResolver.resolve(poolName);
}
finally {
verify(this.mockBeanFactory, never()).containsBean(anyString());
verify(this.mockBeanFactory, never()).getBean(anyString(), any(Pool.class));
}
}
@Test
public void resolveUnresolvablePoolByBlankNameReturnsNull() {
assertThat(testResolveUnresolvablePoolByInvalidName(" ")).isNull();
}
@Test
public void resolveUnresolvablePoolByEmptyNameReturnsNull() {
assertThat(testResolveUnresolvablePoolByInvalidName("")).isNull();
}
@Test
public void resolveUnresolvablePoolByNullNameReturnsNull() {
assertThat(testResolveUnresolvablePoolByInvalidName(null)).isNull();
}
@Test
public void resolvePoolWhenBeanFactoryDoesNotContainPoolBeanByNameReturnsNull() {
when(this.mockBeanFactory.containsBean(anyString())).thenReturn(false);
assertThat(this.poolResolver.resolve("TestPool")).isNull();
verify(this.mockBeanFactory, times(1)).containsBean(eq("TestPool"));
verify(this.mockBeanFactory, never()).getBean(anyString(), eq(Pool.class));
}
@Test(expected = BeanNotOfRequiredTypeException.class)
public void resolvePoolWhenBeanFactoryContainsBeanByPoolNameButNotAsAPoolType() {
when(this.mockBeanFactory.containsBean(anyString())).thenReturn(true);
when(this.mockBeanFactory.getBean(anyString(), eq(Pool.class)))
.thenThrow(new BeanNotOfRequiredTypeException("TestPool", Pool.class, Object.class));
this.poolResolver.resolve("TestPool");
}
}