From d69bdd418ae439c318ea65080cdee86255ad352a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20B=C4=85czkowski?= <36934780+Bouncheck@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:54:48 +0200 Subject: [PATCH] Replace Resolver implementations with library solution (#354) Removes old Resolver implementations. Removes Resolver "hooks" that were added in core code. Adds org.burningwave:tools dependency as the preferred solution. Adds MultimapHostResolver implementation allowing for one-to-many mapping of hostnames to ips. Adds MultimapHostResolverProvider as a replacement for ResolverProvider. Adjusts MockResolverIT to use new replacement. --- .../driver/internal/core/ContactPoints.java | 5 +- .../Ec2MultiRegionAddressTranslator.java | 6 +- .../internal/core/channel/ChannelFactory.java | 6 +- .../internal/core/metadata/SniEndPoint.java | 5 +- .../resolver/AbstractResolverFactory.java | 5 - .../internal/core/resolver/Resolver.java | 48 -------- .../core/resolver/ResolverProvider.java | 55 --------- .../defaultResolver/DefaultResolver.java | 47 -------- .../DefaultResolverFactory.java | 23 ---- .../resolver/mockResolver/MockResolver.java | 81 ------------- .../mockResolver/MockResolverFactory.java | 64 ---------- .../MockResolverResultSource.java | 5 - .../core/resolver/mockResolver/Response.java | 18 --- .../mockResolver/UnknownHostResponse.java | 20 ---- .../resolver/mockResolver/ValidResponse.java | 18 --- .../core/resolver/ResolverProviderTest.java | 52 -------- integration-tests/pom.xml | 5 + .../driver/core/resolver/MockResolverIT.java | 41 ++----- .../core/resolver/MultimapHostResolver.java | 113 ++++++++++++++++++ .../MultimapHostResolverProvider.java | 32 +++++ .../resources/burningwave.static.properties | 4 + pom.xml | 5 + 22 files changed, 173 insertions(+), 485 deletions(-) delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/AbstractResolverFactory.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/Resolver.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/ResolverProvider.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolver.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolverFactory.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolver.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverFactory.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverResultSource.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/Response.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/UnknownHostResponse.java delete mode 100644 core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/ValidResponse.java delete mode 100644 core/src/test/java/com/datastax/oss/driver/internal/core/resolver/ResolverProviderTest.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolver.java create mode 100644 integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolverProvider.java create mode 100644 integration-tests/src/test/resources/burningwave.static.properties diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java b/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java index f60f3dbe041..1ed2a1cebf3 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/ContactPoints.java @@ -19,8 +19,6 @@ import com.datastax.oss.driver.api.core.metadata.EndPoint; import com.datastax.oss.driver.internal.core.metadata.DefaultEndPoint; -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import com.datastax.oss.driver.internal.core.resolver.ResolverProvider; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet; import com.datastax.oss.driver.shaded.guava.common.collect.Sets; import java.net.InetAddress; @@ -37,7 +35,6 @@ /** Utility class to handle the initial contact points passed to the driver. */ public class ContactPoints { private static final Logger LOG = LoggerFactory.getLogger(ContactPoints.class); - private static Resolver RESOLVER = ResolverProvider.getResolver(ContactPoints.class); public static Set merge( Set programmaticContactPoints, List configContactPoints, boolean resolve) { @@ -75,7 +72,7 @@ private static Set extract(String spec, boolean resolve) { return ImmutableSet.of(InetSocketAddress.createUnresolved(host, port)); } else { try { - InetAddress[] inetAddresses = RESOLVER.getAllByName(host); + InetAddress[] inetAddresses = InetAddress.getAllByName(host); if (inetAddresses.length > 1) { LOG.info( "Contact point {} resolves to multiple addresses, will use them all ({})", diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Ec2MultiRegionAddressTranslator.java b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Ec2MultiRegionAddressTranslator.java index 1a239d37955..88e6cdb3bb2 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Ec2MultiRegionAddressTranslator.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/addresstranslation/Ec2MultiRegionAddressTranslator.java @@ -19,8 +19,6 @@ import com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import com.datastax.oss.driver.internal.core.resolver.ResolverProvider; import com.datastax.oss.driver.internal.core.util.Loggers; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; @@ -59,8 +57,6 @@ public class Ec2MultiRegionAddressTranslator implements AddressTranslator { private static final Logger LOG = LoggerFactory.getLogger(Ec2MultiRegionAddressTranslator.class); - private static Resolver RESOLVER = - ResolverProvider.getResolver(Ec2MultiRegionAddressTranslator.class); private final DirContext ctx; private final String logPrefix; @@ -98,7 +94,7 @@ public InetSocketAddress translate(@NonNull InetSocketAddress socketAddress) { return socketAddress; } - InetAddress translatedAddress = RESOLVER.getByName(domainName); + InetAddress translatedAddress = InetAddress.getByName(domainName); LOG.debug("[{}] Resolved {} to {}", logPrefix, address, translatedAddress); return new InetSocketAddress(translatedAddress, socketAddress.getPort()); } catch (Exception e) { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java index 73ed8178e6e..02898a1fedd 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/channel/ChannelFactory.java @@ -42,8 +42,6 @@ import com.datastax.oss.driver.internal.core.metrics.SessionMetricUpdater; import com.datastax.oss.driver.internal.core.protocol.FrameDecoder; import com.datastax.oss.driver.internal.core.protocol.FrameEncoder; -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import com.datastax.oss.driver.internal.core.resolver.ResolverProvider; import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap; @@ -70,8 +68,6 @@ public class ChannelFactory { private static final Logger LOG = LoggerFactory.getLogger(ChannelFactory.class); - private static Resolver RESOLVER = ResolverProvider.getResolver(ChannelFactory.class); - /** * A value for {@link #productType} that indicates that we are connected to DataStax Cloud. This * value matches the one defined at DSE DB server side at {@code ProductType.java}. @@ -208,7 +204,7 @@ private void connect( nettyOptions.afterBootstrapInitialized(bootstrap); - ChannelFuture connectFuture = bootstrap.connect(RESOLVER.resolve(endPoint.resolve())); + ChannelFuture connectFuture = bootstrap.connect(endPoint.resolve()); connectFuture.addListener( cf -> { diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java index 6330701dc91..ace4e82617d 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/SniEndPoint.java @@ -18,8 +18,6 @@ package com.datastax.oss.driver.internal.core.metadata; import com.datastax.oss.driver.api.core.metadata.EndPoint; -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import com.datastax.oss.driver.internal.core.resolver.ResolverProvider; import com.datastax.oss.driver.shaded.guava.common.primitives.UnsignedBytes; import edu.umd.cs.findbugs.annotations.NonNull; import java.net.InetAddress; @@ -32,7 +30,6 @@ public class SniEndPoint implements EndPoint { private static final AtomicLong OFFSET = new AtomicLong(); - private static Resolver RESOLVER = ResolverProvider.getResolver(SniEndPoint.class); private final InetSocketAddress proxyAddress; private final String serverName; @@ -58,7 +55,7 @@ public String getServerName() { @Override public InetSocketAddress resolve() { try { - InetAddress[] aRecords = RESOLVER.getAllByName(proxyAddress.getHostName()); + InetAddress[] aRecords = InetAddress.getAllByName(proxyAddress.getHostName()); if (aRecords.length == 0) { // Probably never happens, but the JDK docs don't explicitly say so throw new IllegalArgumentException( diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/AbstractResolverFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/AbstractResolverFactory.java deleted file mode 100644 index 5e5ea02ff97..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/AbstractResolverFactory.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver; - -public interface AbstractResolverFactory { - public Resolver getResolver(Class clazz); -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/Resolver.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/Resolver.java deleted file mode 100644 index e682d360e98..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/Resolver.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver; - -import com.datastax.oss.driver.internal.core.resolver.defaultResolver.DefaultResolver; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -/** - * Resolver is a "middleman" class that is meant to serve as a hook point for testing. - * Any time core driver tries to resolve a host defined by hostname, such attempt will - * go through the Resolver first. At that moment Resolver may return custom result it - * was configured to return or simply forward the call to the corresponding InetAddress class - * method. - * - * Some classes are exempt from running through the Resolver and they still call InetAddress directly - * (e.g. {@link com.datastax.dse.driver.internal.core.insights.InsightsClient}). - * By default, driver should use {@link DefaultResolver} - * which should introduce no change in behaviour and redirect all calls to {@link InetAddress). - */ -public interface Resolver { - - /** - * Replaces calls to {@link InetAddress#getByName(String)}. - * - * @param host host to resolve. - * @return an IP address for the given host name. - * @throws UnknownHostException - */ - InetAddress getByName(String host) throws UnknownHostException; - - /** - * Replaces calls to {@link InetAddress#getAllByName(String)} - * - * @param host host to resolve. - * @return an array of all the IP addresses for a given host name. - * @throws UnknownHostException - */ - InetAddress[] getAllByName(String host) throws UnknownHostException; - - /** - * Resolves {@link SocketAddress} returning {@link SocketAddress} To be called just before passing - * {@link SocketAddress}, that may be unresolved, to an another library that is going resolve it. - * - * @param addr SocketAddress with host details - * @return SocketAddress instance with possibly modified contents - */ - SocketAddress resolve(SocketAddress addr); -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/ResolverProvider.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/ResolverProvider.java deleted file mode 100644 index 1fa5d4102a9..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/ResolverProvider.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver; - -import com.datastax.oss.driver.internal.core.resolver.defaultResolver.DefaultResolverFactory; -import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting; - -/** - * Entry point for driver components to getting the {@link Resolver} instances. By default returns - * instances of {@link DefaultResolverFactory}. - */ -public class ResolverProvider { - - private static boolean alreadyInUse = false; - private static boolean alreadySet = false; - private static AbstractResolverFactory defaultResolverFactoryImpl = new DefaultResolverFactory(); - - /** - * Asks factory for new {@link Resolver}. - * - * @param clazz Class that is requesting the {@link Resolver}. - * @return new {@link Resolver}. - */ - public static synchronized Resolver getResolver(Class clazz) { - alreadyInUse = true; - return defaultResolverFactoryImpl.getResolver(clazz); - } - - /** - * Replaces resolver factory with another, possibly producing different implementation of {@link - * Resolver}. - * - * @param resolverFactoryImpl new {@link Resolver} factory. - */ - public static synchronized void setDefaultResolverFactory( - AbstractResolverFactory resolverFactoryImpl) { - if (alreadyInUse) { - throw new IllegalStateException( - "Cannot change default resolver factory: ResolverProvider has already returned " - + "an instance of a Resolver to use. Default resolver factory needs to be set up before first use by any " - + "class."); - } - if (alreadySet) { - throw new IllegalStateException( - "Cannot change default resolver factory: this method has already been called. " - + "You can set default resolver factory only once."); - } - alreadySet = true; - defaultResolverFactoryImpl = resolverFactoryImpl; - } - - @VisibleForTesting - static synchronized void resetBooleansForTesting() { - alreadyInUse = false; - alreadySet = false; - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolver.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolver.java deleted file mode 100644 index 9caba5692aa..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolver.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.defaultResolver; - -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -/** - * Resolver implementation that forwards all calls to {@link InetAddress} or returns the arguments - * unmodified. - */ -public class DefaultResolver implements Resolver { - - DefaultResolver() {} - - /** - * Equivalent to {@link InetAddress#getByName(String)}. - * - * @throws UnknownHostException - */ - @Override - public InetAddress getByName(String host) throws UnknownHostException { - return InetAddress.getByName(host); - } - - /** - * Equivalent to {@link InetAddress#getAllByName(String)}. - * - * @throws UnknownHostException - */ - @Override - public InetAddress[] getAllByName(String host) throws UnknownHostException { - return InetAddress.getAllByName(host); - } - - /** - * Returns {@link SocketAddress} as is. No reason to resolve it here, it is supposed to be done by - * a library that is going to consume the result. - * - * @param addr {@link SocketAddress}. - * @return the very same addr. - */ - @Override - public SocketAddress resolve(SocketAddress addr) { - return addr; - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolverFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolverFactory.java deleted file mode 100644 index b11f9a7626b..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/defaultResolver/DefaultResolverFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.defaultResolver; - -import com.datastax.oss.driver.internal.core.resolver.AbstractResolverFactory; - -/** - * Produces instances of {@link - * com.datastax.oss.driver.internal.core.resolver.defaultResolver.DefaultResolver}. - */ -public class DefaultResolverFactory implements AbstractResolverFactory { - - /** - * Returns new {@link - * com.datastax.oss.driver.internal.core.resolver.defaultResolver.DefaultResolver} instance. - * - * @param clazz Class for which the instance is being created. - * @return new {@link - * com.datastax.oss.driver.internal.core.resolver.defaultResolver.DefaultResolver} instance. - */ - @Override - public DefaultResolver getResolver(Class clazz) { - return new DefaultResolver(); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolver.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolver.java deleted file mode 100644 index 4f9f100bdee..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolver.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -/** Resolver implementation that allows returning custom results. */ -public class MockResolver implements Resolver { - private final MockResolverResultSource resultSource; - - MockResolver(MockResolverResultSource resultSource) { - this.resultSource = resultSource; - } - - /** - * Returns first {@link InetAddress} from overrided results {@link Response} if one is present. - * Otherwise forwards the call to {@link InetAddress#getByName(String)} - * - * @param host host to resolve. - * @return address. - * @throws UnknownHostException - */ - @Override - public InetAddress getByName(String host) throws UnknownHostException { - Response response = this.resultSource.getResponse(host); - if (response == null) { - return InetAddress.getByName(host); - } - return response.result()[0]; - } - - /** - * Returns overrided results for provided {@code host}, if one is present, otherwise the call to - * Otherwise forwards the call to {@link InetAddress#getAllByName(String)} - * - * @param host host to resolve. - * @return address. - * @throws UnknownHostException - */ - @Override - public InetAddress[] getAllByName(String host) throws UnknownHostException { - Response response = this.resultSource.getResponse(host); - if (response == null) { - return InetAddress.getAllByName(host); - } - return response.result(); - } - - /** - * If {@code addr} is an resolved {@link InetSocketAddress}, or there is no response overriding - * for the it's host, or {@code addr} is something else, it returns {@code addr} as is. Otherwise - * it returns overrided response, if overrided response throws {@link UnknownHostException}, it - * emulates it by returning unresolved {@link InetSocketAddress} with bogus host. - * - * @param addr SocketAddress to modify. - * @return possibly new SocketAddress. - */ - @Override - public SocketAddress resolve(SocketAddress addr) { - if (!(addr instanceof InetSocketAddress)) { - return addr; - } - InetSocketAddress inetSockAddr = ((InetSocketAddress) addr); - if (!inetSockAddr.isUnresolved()) { - return addr; - } - String hostname = inetSockAddr.getHostName(); - int port = inetSockAddr.getPort(); - Response response = this.resultSource.getResponse(hostname); - if (response == null) { - return addr; - } - try { - return new InetSocketAddress(response.result()[0], port); - } catch (UnknownHostException e) { - return InetSocketAddress.createUnresolved(hostname + ".bad.host.115t87", port); - } - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverFactory.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverFactory.java deleted file mode 100644 index 280e8f521d8..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverFactory.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -import com.datastax.oss.driver.internal.core.resolver.AbstractResolverFactory; -import com.datastax.oss.driver.internal.core.resolver.Resolver; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * Produces instances of {@link MockResolver}. All {@link Resolver} instances produced by instance - * of this class return results sourced by the factory. if {@code defaultResponse} is not set, it - * produces same results as `DefaultResolver` for hosts that are not in the {@code responses} - */ -public class MockResolverFactory implements AbstractResolverFactory, MockResolverResultSource { - private final ConcurrentMap responses = new ConcurrentHashMap<>(); - private Response defaultResponse; - - @Override - public Response getResponse(String hostname) { - return responses.getOrDefault(hostname, defaultResponse); - } - - /** - * Set the result for calls to {@link MockResolverFactory#getResponse(String)} for hostnames that - * do not have custom mappings. - * - * @param response new default response. - */ - @SuppressWarnings("unused") - public void setDefaultResponse(Response response) { - this.defaultResponse = response; - } - - /** - * Add provided mappings to the current mappings. - * - * @param map mappings to merge in. - */ - @SuppressWarnings("unused") - public void updateResponses(Map map) { - responses.putAll(map); - } - - /** - * Adds a single response to the current mappings. - * - * @param address host - key of the mapping. - * @param response value of the mapping. - */ - public void updateResponse(String address, Response response) { - responses.put(address, response); - } - - /** - * Returns new {@link MockResolver} instance. - * - * @param clazz Class for which the instance is being created. - * @return new {@link MockResolver} instance. - */ - @Override - public MockResolver getResolver(Class clazz) { - return new MockResolver(this); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverResultSource.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverResultSource.java deleted file mode 100644 index 8a79b59c8c2..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/MockResolverResultSource.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -public interface MockResolverResultSource { - Response getResponse(String hostname); -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/Response.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/Response.java deleted file mode 100644 index b2e32cea301..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/Response.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Represents results returned by {@link - * com.datastax.oss.driver.internal.core.resolver.mockResolver.MockResolverFactory}. - */ -public interface Response { - /** - * Underlying result of this Response. - * - * @return result of this Response. - * @throws UnknownHostException - */ - InetAddress[] result() throws UnknownHostException; -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/UnknownHostResponse.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/UnknownHostResponse.java deleted file mode 100644 index a5f37f8ee77..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/UnknownHostResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** Unsuccessful response. Throws on {@code result()} calls. */ -@SuppressWarnings("unused") -public class UnknownHostResponse implements Response { - private final String message; - - @SuppressWarnings("unused") - public UnknownHostResponse(String message) { - this.message = message; - } - - @Override - public InetAddress[] result() throws UnknownHostException { - throw new UnknownHostException(message); - } -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/ValidResponse.java b/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/ValidResponse.java deleted file mode 100644 index ed42b4735b6..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/resolver/mockResolver/ValidResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver.mockResolver; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** Successful response with an array of valid IPs. */ -public class ValidResponse implements Response { - private final InetAddress[] list; - - public ValidResponse(InetAddress[] list) { - this.list = list; - } - - @Override - public InetAddress[] result() throws UnknownHostException { - return list; - } -} diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/resolver/ResolverProviderTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/resolver/ResolverProviderTest.java deleted file mode 100644 index a1d98932af3..00000000000 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/resolver/ResolverProviderTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.datastax.oss.driver.internal.core.resolver; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import com.datastax.oss.driver.internal.core.resolver.mockResolver.MockResolverFactory; -import org.junit.Before; -import org.junit.Test; - -public class ResolverProviderTest { - - @Before - public void resetState() { - ResolverProvider.resetBooleansForTesting(); - } - - @Test(expected = IllegalStateException.class) - public void should_not_allow_setting_twice() { - try { - MockResolverFactory first = new MockResolverFactory(); - MockResolverFactory second = new MockResolverFactory(); - ResolverProvider.setDefaultResolverFactory(first); - ResolverProvider.setDefaultResolverFactory(second); - } catch (IllegalStateException ex) { - assertThat(ex.getMessage()) - .isEqualTo( - "Cannot change default resolver factory: this method has already been called. You can set " - + "default resolver factory only once."); - throw ex; - } - } - - @Test(expected = IllegalStateException.class) - public void should_not_allow_setting_once_in_use() { - try { - ResolverProvider.getResolver(ResolverProviderTest.class); - MockResolverFactory first = new MockResolverFactory(); - ResolverProvider.setDefaultResolverFactory(first); - } catch (IllegalStateException ex) { - assertThat(ex.getMessage()) - .isEqualTo( - "Cannot change default resolver factory: ResolverProvider has already returned an instance of a " - + "Resolver to use. Default resolver factory needs to be set up before first use by any class."); - throw ex; - } - } - - @Test - public void should_allow_setting_once() { - MockResolverFactory first = new MockResolverFactory(); - ResolverProvider.setDefaultResolverFactory(first); - } -} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 60631228e77..dfbada2ca4c 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -228,6 +228,11 @@ esri-geometry-api test + + org.burningwave + tools + test + diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MockResolverIT.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MockResolverIT.java index 5b8c3c907b9..6dc2d2ca77f 100644 --- a/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MockResolverIT.java +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MockResolverIT.java @@ -37,19 +37,13 @@ import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge; import com.datastax.oss.driver.categories.IsolatedTests; import com.datastax.oss.driver.internal.core.config.typesafe.DefaultProgrammaticDriverConfigLoaderBuilder; -import com.datastax.oss.driver.internal.core.resolver.ResolverProvider; -import com.datastax.oss.driver.internal.core.resolver.mockResolver.MockResolverFactory; -import com.datastax.oss.driver.internal.core.resolver.mockResolver.ValidResponse; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.UnknownHostException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; import org.slf4j.Logger; @@ -59,23 +53,17 @@ public class MockResolverIT { private static final Logger LOG = LoggerFactory.getLogger(MockResolverIT.class); - private static final MockResolverFactory RESOLVER_FACTORY = new MockResolverFactory(); private static final int CLUSTER_WAIT_SECONDS = 60; // Maximal wait time for cluster nodes to get up - @BeforeClass - public static void setUpResolver() { - ResolverProvider.setDefaultResolverFactory(RESOLVER_FACTORY); - } - @Test public void should_connect_with_mocked_hostname() { CcmBridge.Builder ccmBridgeBuilder = CcmBridge.builder().withNodes(1).withIpPrefix("127.0.1."); try (CcmBridge ccmBridge = ccmBridgeBuilder.build()) { - RESOLVER_FACTORY.updateResponse( - "test.cluster.fake", - new ValidResponse(new InetAddress[] {getNodeInetAddress(ccmBridge, 1)})); + MultimapHostResolverProvider.removeResolverEntries("test.cluster.fake"); + MultimapHostResolverProvider.addResolverEntry( + "test.cluster.fake", ccmBridge.getNodeIpAddress(1)); ccmBridge.create(); ccmBridge.start(); @@ -128,14 +116,13 @@ public void replace_cluster_test() { try (CcmBridge ccmBridge = CcmBridge.builder().withNodes(numberOfNodes).withIpPrefix("127.0.1.").build()) { - RESOLVER_FACTORY.updateResponse( - "test.cluster.fake", - new ValidResponse( - new InetAddress[] { - getNodeInetAddress(ccmBridge, 1), - getNodeInetAddress(ccmBridge, 2), - getNodeInetAddress(ccmBridge, 3) - })); + MultimapHostResolverProvider.removeResolverEntries("test.cluster.fake"); + MultimapHostResolverProvider.addResolverEntry( + "test.cluster.fake", ccmBridge.getNodeIpAddress(1)); + MultimapHostResolverProvider.addResolverEntry( + "test.cluster.fake", ccmBridge.getNodeIpAddress(2)); + MultimapHostResolverProvider.addResolverEntry( + "test.cluster.fake", ccmBridge.getNodeIpAddress(3)); ccmBridge.create(); ccmBridge.start(); session = builder.build(); @@ -250,12 +237,4 @@ public void run_replace_test_20_times() { replace_cluster_test(); } } - - private static InetAddress getNodeInetAddress(CcmBridge ccmBridge, int nodeid) { - try { - return InetAddress.getByName(ccmBridge.getNodeIpAddress(nodeid)); - } catch (UnknownHostException e) { - return null; - } - } } diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolver.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolver.java new file mode 100644 index 00000000000..cf2b373642c --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolver.java @@ -0,0 +1,113 @@ +package com.datastax.oss.driver.core.resolver; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.burningwave.tools.net.HostResolutionRequestInterceptor; +import org.burningwave.tools.net.HostResolver; +import org.burningwave.tools.net.IPAddressUtil; + +/** Variation on MappedHostResolver that uses Multimap instead. Allows duplicate entries. */ +public class MultimapHostResolver implements HostResolver { + protected Multimap hostAliases; + + public MultimapHostResolver(Multimap hostAliases) { + this.hostAliases = hostAliases; + } + + public MultimapHostResolver() { + this.hostAliases = ArrayListMultimap.create(); + } + + @Override + public Collection getAllAddressesForHostName(Map argumentMap) { + String hostName = (String) getMethodArguments(argumentMap)[0]; + List inetAddresses = new ArrayList<>(); + + if (hostAliases.containsKey(hostName)) { + Collection iPAddresses = hostAliases.get(hostName); + try { + for (String iPAddress : iPAddresses) { + inetAddresses.add( + InetAddress.getByAddress( + hostName, IPAddressUtil.INSTANCE.textToNumericFormat(iPAddress))); + } + } catch (UnknownHostException e) { + + } + } + return inetAddresses; + } + + @Override + public Collection getAllHostNamesForHostAddress(Map argumentMap) { + byte[] address = (byte[]) getMethodArguments(argumentMap)[0]; + Collection hostNames = new ArrayList<>(); + String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(address); + for (Map.Entry entry : hostAliases.entries()) { + if (entry.getValue().equals(iPAddress)) { + hostNames.add(entry.getKey()); + break; + } + } + return hostNames; + } + + public synchronized MultimapHostResolver putHost(String hostname, String iP) { + Multimap hostAliases = ArrayListMultimap.create(this.hostAliases); + hostAliases.put(hostname, iP); + this.hostAliases = hostAliases; + return this; + } + + public synchronized MultimapHostResolver removeHost(String hostname) { + Multimap hostAliases = ArrayListMultimap.create(this.hostAliases); + hostAliases.removeAll(hostname); + this.hostAliases = hostAliases; + return this; + } + + public synchronized MultimapHostResolver removeHostForIP(String iP) { + Multimap hostAliases = ArrayListMultimap.create(this.hostAliases); + Iterator> hostAliasesIterator = hostAliases.entries().iterator(); + while (hostAliasesIterator.hasNext()) { + Map.Entry host = hostAliasesIterator.next(); + if (host.getValue().contains(iP)) { + hostAliasesIterator.remove(); + } + } + this.hostAliases = hostAliases; + return this; + } + + @Override + public boolean isReady(HostResolutionRequestInterceptor hostResolverService) { + return HostResolver.super.isReady(hostResolverService) && obtainsResponseForMappedHost(); + } + + protected synchronized boolean obtainsResponseForMappedHost() { + String hostNameForTest = null; + if (hostAliases.isEmpty()) { + putHost(hostNameForTest = UUID.randomUUID().toString(), "127.0.0.1"); + } + try { + for (String hostname : hostAliases.keySet()) { + InetAddress.getByName(hostname); + } + return true; + } catch (UnknownHostException exc) { + return false; + } finally { + if (hostNameForTest != null) { + removeHost(hostNameForTest); + } + } + } +} diff --git a/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolverProvider.java b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolverProvider.java new file mode 100644 index 00000000000..40b5c729924 --- /dev/null +++ b/integration-tests/src/test/java/com/datastax/oss/driver/core/resolver/MultimapHostResolverProvider.java @@ -0,0 +1,32 @@ +package com.datastax.oss.driver.core.resolver; + +import org.burningwave.tools.net.DefaultHostResolver; +import org.burningwave.tools.net.HostResolutionRequestInterceptor; + +public class MultimapHostResolverProvider { + private static volatile MultimapHostResolver resolver = null; + + private MultimapHostResolverProvider() {} + + public static synchronized void setResolver(MultimapHostResolver newResolver) { + if (resolver != null) { + throw new IllegalStateException("Resolver is already set. Cannot set new."); + } + resolver = newResolver; + HostResolutionRequestInterceptor.INSTANCE.install(resolver, DefaultHostResolver.INSTANCE); + } + + public static synchronized void addResolverEntry(String hostname, String address) { + if (resolver == null) { + setResolver(new MultimapHostResolver()); + } + resolver.putHost(hostname, address); + } + + public static synchronized void removeResolverEntries(String hostname) { + if (resolver == null) { + return; + } + resolver.removeHost(hostname); + } +} diff --git a/integration-tests/src/test/resources/burningwave.static.properties b/integration-tests/src/test/resources/burningwave.static.properties new file mode 100644 index 00000000000..7108b42c0fb --- /dev/null +++ b/integration-tests/src/test/resources/burningwave.static.properties @@ -0,0 +1,4 @@ +managed-logger.repository=autodetect +managed-logger.repository.enabled=false +banner.hide=true +priority-of-this-configuration=1000 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 414ec6b5eb2..c473c1062ae 100644 --- a/pom.xml +++ b/pom.xml @@ -458,6 +458,11 @@ blockhound-junit-platform 1.0.8.RELEASE + + org.burningwave + tools + 0.26.2 +