Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.datastax.oss.driver.api.core.config;

import com.datastax.oss.driver.api.core.session.SessionBuilder;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import net.jcip.annotations.Immutable;

/**
* Configuration for client routes, used in PrivateLink-style deployments.
*
* <p>Client routes enable the driver to discover and connect to nodes through a load balancer (such
* as AWS PrivateLink) by reading endpoint mappings from the {@code system.client_routes} table.
* Each endpoint is identified by a connection ID and maps to specific node addresses.
*
* <p>This configuration is mutually exclusive with a user-provided {@link
* com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator}. If client routes are
* configured, the driver will use its internal client routes handler for address translation.
*
* <p>Example usage:
*
* <pre>{@code
* ClientRoutesConfig config = ClientRoutesConfig.builder()
* .addEndpoint(new ClientRoutesEndpoint(
* UUID.fromString("12345678-1234-1234-1234-123456789012"),
* "my-privatelink.us-east-1.aws.scylladb.com:9042"))
* .build();
*
* CqlSession session = CqlSession.builder()
* .withClientRoutesConfig(config)
* .build();
* }</pre>
*
* @see SessionBuilder#withClientRoutesConfig(ClientRoutesConfig)
* @see ClientRoutesEndpoint
*/
@Immutable
public class ClientRoutesConfig {

private final List<ClientRoutesEndpoint> endpoints;
private final String tableName;

private ClientRoutesConfig(List<ClientRoutesEndpoint> endpoints, String tableName) {
if (endpoints == null || endpoints.isEmpty()) {
throw new IllegalArgumentException("At least one endpoint must be specified");
}
this.endpoints = Collections.unmodifiableList(new ArrayList<>(endpoints));
this.tableName = tableName;
}

/**
* Returns the list of configured endpoints.
*
* @return an immutable list of endpoints.
*/
@NonNull
public List<ClientRoutesEndpoint> getEndpoints() {
return endpoints;
}

/**
* Returns the name of the system table to query for client routes.
*
* @return the table name, or null to use the default ({@code system.client_routes}).
*/
@Nullable
public String getTableName() {
return tableName;
}

/**
* Creates a new builder for constructing a {@link ClientRoutesConfig}.
*
* @return a new builder instance.
*/
@NonNull
public static Builder builder() {
return new Builder();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ClientRoutesConfig)) {
return false;
}
ClientRoutesConfig that = (ClientRoutesConfig) o;
return endpoints.equals(that.endpoints) && Objects.equals(tableName, that.tableName);
}

@Override
public int hashCode() {
return Objects.hash(endpoints, tableName);
}

@Override
public String toString() {
return "ClientRoutesConfig{"
+ "endpoints="
+ endpoints
+ ", tableName='"
+ tableName
+ '\''
+ '}';
}

/** Builder for {@link ClientRoutesConfig}. */
public static class Builder {
private final List<ClientRoutesEndpoint> endpoints = new ArrayList<>();
private String tableName;

/**
* Adds an endpoint to the configuration.
*
* @param endpoint the endpoint to add (must not be null).
* @return this builder.
*/
@NonNull
public Builder addEndpoint(@NonNull ClientRoutesEndpoint endpoint) {
this.endpoints.add(Objects.requireNonNull(endpoint, "endpoint must not be null"));
return this;
}

/**
* Sets the endpoints for the configuration, replacing any previously added endpoints.
*
* @param endpoints the endpoints to set (must not be null or empty).
* @return this builder.
*/
@NonNull
public Builder withEndpoints(@NonNull List<ClientRoutesEndpoint> endpoints) {
Objects.requireNonNull(endpoints, "endpoints must not be null");
this.endpoints.clear();
this.endpoints.addAll(endpoints);
return this;
}

/**
* Sets the name of the system table to query for client routes.
*
* <p>This is primarily useful for testing. If not set, the driver will use the default table
* name from the configuration ({@code system.client_routes}).
*
* @param tableName the table name to use.
* @return this builder.
*/
@NonNull
public Builder withTableName(@Nullable String tableName) {
this.tableName = tableName;
return this;
}

/**
* Builds the {@link ClientRoutesConfig} with the configured endpoints and table name.
*
* @return the new configuration instance.
* @throws IllegalArgumentException if no endpoints have been added.
*/
@NonNull
public ClientRoutesConfig build() {
return new ClientRoutesConfig(endpoints, tableName);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.datastax.oss.driver.api.core.config;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.Objects;
import java.util.UUID;
import net.jcip.annotations.Immutable;

/**
* Represents a client routes endpoint for PrivateLink-style deployments.
*
* <p>Each endpoint corresponds to a connection ID in the {@code system.client_routes} table, with
* an optional connection address that can be used as a seed host for initial connection.
*/
@Immutable
public class ClientRoutesEndpoint {

private final UUID connectionId;
private final String connectionAddr;

/**
* Creates a new endpoint with the given connection ID and no connection address.
*
* @param connectionId the connection ID (must not be null).
*/
public ClientRoutesEndpoint(@NonNull UUID connectionId) {
this(connectionId, null);
}

/**
* Creates a new endpoint with the given connection ID and connection address.
*
* @param connectionId the connection ID (must not be null).
* @param connectionAddr the connection address to use as a seed host (may be null).
*/
public ClientRoutesEndpoint(@NonNull UUID connectionId, @Nullable String connectionAddr) {
this.connectionId = Objects.requireNonNull(connectionId, "connectionId must not be null");
this.connectionAddr = connectionAddr;
}

/** Returns the connection ID for this endpoint. */
@NonNull
public UUID getConnectionId() {
return connectionId;
}

/**
* Returns the connection address for this endpoint, or null if not specified.
*
* <p>When provided and no explicit contact points are given to the session builder, this address
* will be used as a seed host for the initial connection.
*/
@Nullable
public String getConnectionAddr() {
return connectionAddr;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ClientRoutesEndpoint)) {
return false;
}
ClientRoutesEndpoint that = (ClientRoutesEndpoint) o;
return connectionId.equals(that.connectionId)
&& Objects.equals(connectionAddr, that.connectionAddr);
}

@Override
public int hashCode() {
return Objects.hash(connectionId, connectionAddr);
}

@Override
public String toString() {
return "ClientRoutesEndpoint{"
+ "connectionId="
+ connectionId
+ ", connectionAddr='"
+ connectionAddr
+ '\''
+ '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,17 @@ public enum DefaultDriverOption implements DriverOption {
*/
ADDRESS_TRANSLATOR_CLASS("advanced.address-translator.class"),

/**
* The name of the system table to query for client routes information.
*
* <p>This is used when client routes are configured programmatically via {@link
* com.datastax.oss.driver.api.core.session.SessionBuilder#withClientRoutesConfig}. The default
* value is {@code system.client_routes}.
*
* <p>Value-type: {@link String}
*/
CLIENT_ROUTES_TABLE_NAME("advanced.client-routes.table-name"),

/**
* The native protocol version to use.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ protected static void fillWithDriverDefaults(OptionsMap map) {
map.put(
TypedDriverOption.LOAD_BALANCING_DEFAULT_LWT_REQUEST_ROUTING_METHOD,
"PRESERVE_REPLICA_ORDER");
map.put(TypedDriverOption.CLIENT_ROUTES_TABLE_NAME, "system.client_routes");
}

@Immutable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,9 @@ public String toString() {
DefaultDriverOption.LOAD_BALANCING_DEFAULT_LWT_REQUEST_ROUTING_METHOD,
GenericType.STRING);

public static final TypedDriverOption<String> CLIENT_ROUTES_TABLE_NAME =
new TypedDriverOption<>(DefaultDriverOption.CLIENT_ROUTES_TABLE_NAME, GenericType.STRING);

private static Iterable<TypedDriverOption<?>> introspectBuiltInValues() {
try {
ImmutableList.Builder<TypedDriverOption<?>> result = ImmutableList.builder();
Expand Down
Loading
Loading