DATAGEODE-317 - Add PoolResolver implementation to compose a collection of PoolResolvers.
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 java.util.Arrays;
|
||||
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.data.gemfire.client.PoolResolver;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite of {@link PoolResolver PoolResolvers} functioning as a single {@link PoolResolver}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class ComposablePoolResolver implements PoolResolver {
|
||||
|
||||
/**
|
||||
* Null-safe factory method to compose an array of {@link PoolResolver} objects.
|
||||
*
|
||||
* Preserves order in the composition.
|
||||
*
|
||||
* @param poolResolvers array of {@link PoolResolver} objects to compose.
|
||||
* @return a composition from the array of {@link PoolResolver} objects; may return {@literal null}.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @see #compose(Iterable)
|
||||
*/
|
||||
public static @Nullable PoolResolver compose(@Nullable PoolResolver... poolResolvers) {
|
||||
return compose(Arrays.asList(ArrayUtils.nullSafeArray(poolResolvers, PoolResolver.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe factory method to compose an {@link Iterable} of {@link PoolResolver} objects.
|
||||
*
|
||||
* Preserves order in the composition if the {@link Iterable} collection-like data structure is ordered,
|
||||
* like a {@link java.util.List}).
|
||||
*
|
||||
* @param poolResolvers {@link Iterable} of {@link PoolResolver} objects to compose.
|
||||
* @return a composition from the {@link Iterable} of {@link PoolResolver} objects; may return {@literal null}.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @see java.lang.Iterable
|
||||
* @see #compose(PoolResolver, PoolResolver)
|
||||
*/
|
||||
public static @Nullable PoolResolver compose(@Nullable Iterable<PoolResolver> poolResolvers) {
|
||||
|
||||
PoolResolver current = null;
|
||||
|
||||
for (PoolResolver poolResolver : CollectionUtils.nullSafeIterable(poolResolvers)) {
|
||||
current = compose(current, poolResolver);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe factory method to compose two {@link PoolResolver} objects in a composition.
|
||||
*
|
||||
* @param one first {@link PoolResolver} in the composition.
|
||||
* @param two second {@link PoolResolver} in the composition.
|
||||
* @return a composition from the two {@link PoolResolver} objects. Returns the first {@link PoolResolver}
|
||||
* if the second {@link PoolResolver} is {@literal null}. Returns the second {@link PoolResolver} if the first
|
||||
* {@link PoolResolver} is {@literal null}. Returns {@literal null} if both {@link PoolResolver} arguments
|
||||
* are {@literal null}.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
* @see #ComposablePoolResolver(PoolResolver, PoolResolver)
|
||||
*/
|
||||
public static @Nullable PoolResolver compose(@Nullable PoolResolver one, @Nullable PoolResolver two) {
|
||||
return one == null ? two : two == null ? one : new ComposablePoolResolver(one, two);
|
||||
}
|
||||
|
||||
private final PoolResolver poolResolverOne;
|
||||
private final PoolResolver poolResolverTwo;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link ComposablePoolResolver} initialized and composed of two {@link PoolResolver}
|
||||
* implementations that will function as one.
|
||||
*
|
||||
* @param poolResolverOne first {@link PoolResolver} in the composition order.
|
||||
* @param poolResolverTwo second {@link PoolResolver} in the composition order.
|
||||
* @throws IllegalArgumentException if either the first or second {@link PoolResolver} are {@literal null}.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
*/
|
||||
protected ComposablePoolResolver(PoolResolver poolResolverOne, PoolResolver poolResolverTwo) {
|
||||
|
||||
Assert.notNull(poolResolverOne, "PoolResolver 1 must not be null");
|
||||
Assert.notNull(poolResolverTwo, "PoolResolver 2 must not be null");
|
||||
|
||||
this.poolResolverOne = poolResolverOne;
|
||||
this.poolResolverTwo = poolResolverTwo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the first {@link PoolResolver} in the composition.
|
||||
*
|
||||
* @return a reference to the first {@link PoolResolver} in the composition.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
*/
|
||||
protected @NonNull PoolResolver getPoolResolverOne() {
|
||||
return this.poolResolverOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the second {@link PoolResolver} in the composition.
|
||||
*
|
||||
* @return a reference to the second {@link PoolResolver} in the composition.
|
||||
* @see org.springframework.data.gemfire.client.PoolResolver
|
||||
*/
|
||||
protected @NonNull PoolResolver getPoolResolverTwo() {
|
||||
return this.poolResolverTwo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve a {@link Pool} with the given {@link String name} by delegating to the composed
|
||||
* {@link PoolResolver} objects.
|
||||
*
|
||||
* The first {@link PoolResolver} in the composition to resolve a {@link Pool} with the given {@link String name}
|
||||
* stops the resolution process and returns the target {@link Pool}. If no {@link Pool} with the given
|
||||
* {@link String name} can be resolved by any {@link PoolResolver} in the composition, then {@literal null}
|
||||
* will be returned.
|
||||
*
|
||||
* @param poolName {@link String name} of the {@link Pool} to resolve.
|
||||
* @return the resolved {@link Pool} or {@literal null} if a {@link Pool} with {@link String name}
|
||||
* cannot be resolved.
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see #getPoolResolverOne()
|
||||
* @see #getPoolResolverTwo()
|
||||
*/
|
||||
@Nullable @Override
|
||||
public Pool resolve(@Nullable String poolName) {
|
||||
|
||||
Pool pool = getPoolResolverOne().resolve(poolName);
|
||||
|
||||
return pool != null ? pool : getPoolResolverTwo().resolve(poolName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.data.gemfire.client.PoolResolver;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link ComposablePoolResolver}.
|
||||
*
|
||||
* @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.data.gemfire.client.PoolResolver
|
||||
* @see org.springframework.data.gemfire.client.support.ComposablePoolResolver
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ComposablePoolResolverUnitTests {
|
||||
|
||||
@Mock
|
||||
private Pool mockPool;
|
||||
|
||||
@Mock(name = "one")
|
||||
private PoolResolver mockPoolResolverOne;
|
||||
|
||||
@Mock(name = "two")
|
||||
private PoolResolver mockPoolResolverTwo;
|
||||
|
||||
@Mock(name = "three")
|
||||
private PoolResolver mockPoolResolverThree;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void composeWithArrayOfPoolResolvers() {
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver
|
||||
.compose(this.mockPoolResolverOne, this.mockPoolResolverTwo, this.mockPoolResolverThree);
|
||||
|
||||
assertThat(poolResolver).isInstanceOf(ComposablePoolResolver.class);
|
||||
|
||||
PoolResolver one = ((ComposablePoolResolver) poolResolver).getPoolResolverOne();
|
||||
PoolResolver two = ((ComposablePoolResolver) poolResolver).getPoolResolverTwo();
|
||||
|
||||
assertThat(one).isInstanceOf(ComposablePoolResolver.class);
|
||||
assertThat(((ComposablePoolResolver) one).getPoolResolverOne()).isEqualTo(this.mockPoolResolverOne);
|
||||
assertThat(((ComposablePoolResolver) one).getPoolResolverTwo()).isEqualTo(this.mockPoolResolverTwo);
|
||||
assertThat(two).isEqualTo(this.mockPoolResolverThree);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithArrayContainingSinglePoolResolver() {
|
||||
|
||||
assertThat(ComposablePoolResolver.compose(this.mockPoolResolverOne))
|
||||
.isEqualTo(this.mockPoolResolverOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithArrayContainingNonNullPoolResolverAndNullPoolResolver() {
|
||||
|
||||
PoolResolver[] poolResolvers = { this.mockPoolResolverOne, null };
|
||||
|
||||
assertThat(ComposablePoolResolver.compose(poolResolvers)).isEqualTo(this.mockPoolResolverOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void composeWithArrayContainingNullAndNonNullPoolResolvers() {
|
||||
|
||||
PoolResolver[] poolResolvers = { null, this.mockPoolResolverOne, null, this.mockPoolResolverTwo, null };
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(poolResolvers);
|
||||
|
||||
assertThat(poolResolver).isInstanceOf(ComposablePoolResolver.class);
|
||||
assertThat(((ComposablePoolResolver) poolResolver).getPoolResolverOne()).isEqualTo(this.mockPoolResolverOne);
|
||||
assertThat(((ComposablePoolResolver) poolResolver).getPoolResolverTwo()).isEqualTo(this.mockPoolResolverTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void composeWithArrayContainingOrganizedNullAndNonNullPoolResolvers() {
|
||||
|
||||
PoolResolver[] poolResolvers = {
|
||||
null, this.mockPoolResolverOne, this.mockPoolResolverTwo, null, this.mockPoolResolverThree, null, null
|
||||
};
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(poolResolvers);
|
||||
|
||||
assertThat(poolResolver).isInstanceOf(ComposablePoolResolver.class);
|
||||
|
||||
PoolResolver one = ((ComposablePoolResolver) poolResolver).getPoolResolverOne();
|
||||
PoolResolver two = ((ComposablePoolResolver) poolResolver).getPoolResolverTwo();
|
||||
|
||||
assertThat(one).isInstanceOf(ComposablePoolResolver.class);
|
||||
assertThat(((ComposablePoolResolver) one).getPoolResolverOne()).isEqualTo(this.mockPoolResolverOne);
|
||||
assertThat(((ComposablePoolResolver) one).getPoolResolverTwo()).isEqualTo(this.mockPoolResolverTwo);
|
||||
assertThat(two).isEqualTo(this.mockPoolResolverThree);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithEmptyArrayReturnsNull() {
|
||||
assertThat(ComposablePoolResolver.compose()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithNullArrayIsNullSafe() {
|
||||
assertThat(ComposablePoolResolver.compose((PoolResolver[]) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithNullIterableIsNullSafe() {
|
||||
assertThat(ComposablePoolResolver.compose((Iterable<PoolResolver>) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithAllNullPoolResolvers() {
|
||||
assertThat(ComposablePoolResolver.compose(null, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithSingleNullPoolResolver() {
|
||||
|
||||
assertThat(ComposablePoolResolver.compose(this.mockPoolResolverOne, null))
|
||||
.isEqualTo(this.mockPoolResolverOne);
|
||||
|
||||
assertThat(ComposablePoolResolver.compose(null, this.mockPoolResolverTwo))
|
||||
.isEqualTo(this.mockPoolResolverTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithTwoNonNullPoolResolvers() {
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
assertThat(poolResolver).isInstanceOf(ComposablePoolResolver.class);
|
||||
assertThat(((ComposablePoolResolver) poolResolver).getPoolResolverOne()).isEqualTo(this.mockPoolResolverOne);
|
||||
assertThat(((ComposablePoolResolver) poolResolver).getPoolResolverTwo()).isEqualTo(this.mockPoolResolverTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructComposablePoolResolver() {
|
||||
|
||||
ComposablePoolResolver poolResolver =
|
||||
new ComposablePoolResolver(this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
assertThat(poolResolver).isNotNull();
|
||||
assertThat(poolResolver.getPoolResolverOne()).isEqualTo(this.mockPoolResolverOne);
|
||||
assertThat(poolResolver.getPoolResolverTwo()).isEqualTo(this.mockPoolResolverTwo);
|
||||
}
|
||||
|
||||
public void testConstructComposablePoolResolverWithNullPoolResolver(Supplier<ComposablePoolResolver> constructor,
|
||||
String expectedMessage) {
|
||||
|
||||
try {
|
||||
constructor.get();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage(expectedMessage);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructComposablePoolResolverWithNullPoolResolverAsFirstArgument() {
|
||||
testConstructComposablePoolResolverWithNullPoolResolver(
|
||||
() -> new ComposablePoolResolver(null, this.mockPoolResolverTwo),
|
||||
"PoolResolver 1 must not be null");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructComposablePoolResolverWithNullPoolResolverAsSecondArgument() {
|
||||
testConstructComposablePoolResolverWithNullPoolResolver(
|
||||
() -> new ComposablePoolResolver(this.mockPoolResolverOne, null),
|
||||
"PoolResolver 2 must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveReturnsFromFirstPoolResolver() {
|
||||
|
||||
when(this.mockPoolResolverOne.resolve(anyString())).thenReturn(this.mockPool);
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
assertThat(poolResolver.resolve("TestPool")).isEqualTo(this.mockPool);
|
||||
|
||||
verify(this.mockPoolResolverOne, times(1)).resolve(eq("TestPool"));
|
||||
verify(this.mockPoolResolverTwo, never()).resolve(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveReturnsFromSecondPoolResolver() {
|
||||
|
||||
when(this.mockPoolResolverTwo.resolve(anyString())).thenReturn(this.mockPool);
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
assertThat(poolResolver.resolve("TestPool")).isEqualTo(this.mockPool);
|
||||
|
||||
verify(this.mockPoolResolverOne, times(1)).resolve(eq("TestPool"));
|
||||
verify(this.mockPoolResolverTwo, times(1)).resolve(eq("TestPool"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void resolveReturnsPoolFromLastPoolResolverInOrder() {
|
||||
|
||||
when(this.mockPoolResolverTwo.resolve(anyString())).thenReturn(this.mockPool);
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(null, this.mockPoolResolverThree,
|
||||
null , null, this.mockPoolResolverOne, null, this.mockPoolResolverTwo, null, null);
|
||||
|
||||
assertThat(poolResolver.resolve("TestPool")).isEqualTo(this.mockPool);
|
||||
|
||||
InOrder ordered = inOrder(this.mockPoolResolverThree, this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
ordered.verify(this.mockPoolResolverThree, times(1)).resolve(eq("TestPool"));
|
||||
ordered.verify(this.mockPoolResolverOne, times(1)).resolve(eq("TestPool"));
|
||||
ordered.verify(this.mockPoolResolverTwo, times(1)).resolve(eq("TestPool"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveReturnsNull() {
|
||||
|
||||
PoolResolver poolResolver = ComposablePoolResolver.compose(this.mockPoolResolverOne, this.mockPoolResolverTwo);
|
||||
|
||||
assertThat(poolResolver.resolve("TestPool")).isNull();
|
||||
|
||||
verify(this.mockPoolResolverOne, times(1)).resolve(eq("TestPool"));
|
||||
verify(this.mockPoolResolverTwo, times(1)).resolve(eq("TestPool"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user