Skip to content

Introduce bolt_agent #1424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
21 changes: 2 additions & 19 deletions driver/src/main/java/org/neo4j/driver/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
*/
package org.neo4j.driver;

import static java.lang.String.format;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
import static org.neo4j.driver.internal.util.DriverInfoUtil.driverVersion;

import java.io.File;
import java.io.Serial;
Expand Down Expand Up @@ -345,7 +345,7 @@ public static final class ConfigBuilder {
private long idleTimeBeforeConnectionTest = PoolSettings.DEFAULT_IDLE_TIME_BEFORE_CONNECTION_TEST;
private long maxConnectionLifetimeMillis = PoolSettings.DEFAULT_MAX_CONNECTION_LIFETIME;
private long connectionAcquisitionTimeoutMillis = PoolSettings.DEFAULT_CONNECTION_ACQUISITION_TIMEOUT;
private String userAgent = format("neo4j-java/%s", driverVersion());
private String userAgent = driverVersion();
private final SecuritySettings.SecuritySettingsBuilder securitySettingsBuilder =
new SecuritySettings.SecuritySettingsBuilder();
private long routingTablePurgeDelayMillis = RoutingSettings.STALE_ROUTING_TABLE_PURGE_DELAY_MS;
Expand Down Expand Up @@ -748,23 +748,6 @@ public ConfigBuilder withNotificationConfig(NotificationConfig notificationConfi
return this;
}

/**
* Extracts the driver version from the driver jar MANIFEST.MF file.
*/
private static String driverVersion() {
// "Session" is arbitrary - the only thing that matters is that the class we use here is in the
// 'org.neo4j.driver' package, because that is where the jar manifest specifies the version.
// This is done as part of the build, adding a MANIFEST.MF file to the generated jarfile.
Package pkg = Session.class.getPackage();
if (pkg != null && pkg.getImplementationVersion() != null) {
return pkg.getImplementationVersion();
}

// If there is no version, we're not running from a jar file, but from raw compiled class files.
// This should only happen during development, so call the version 'dev'.
return "dev";
}

/**
* Create a config instance from this builder.
*
Expand Down
21 changes: 21 additions & 0 deletions driver/src/main/java/org/neo4j/driver/internal/BoltAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* 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
*
* 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 org.neo4j.driver.internal;

public record BoltAgent(String product, String platform, String language, String languageDetails) {}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.neo4j.driver.internal.security.StaticAuthTokenManager;
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.spi.ConnectionProvider;
import org.neo4j.driver.internal.util.DriverInfoUtil;
import org.neo4j.driver.internal.util.Futures;
import org.neo4j.driver.net.ServerAddressResolver;

Expand Down Expand Up @@ -141,7 +142,8 @@ protected ConnectionPool createConnectionPool(
Clock clock = createClock();
ConnectionSettings settings =
new ConnectionSettings(authTokenManager, config.userAgent(), config.connectionTimeoutMillis());
ChannelConnector connector = createConnector(settings, securityPlan, config, clock, routingContext);
var boltAgent = DriverInfoUtil.boltAgent();
ChannelConnector connector = createConnector(settings, securityPlan, config, clock, routingContext, boltAgent);
PoolSettings poolSettings = new PoolSettings(
config.maxConnectionPoolSize(),
config.connectionAcquisitionTimeoutMillis(),
Expand Down Expand Up @@ -179,15 +181,17 @@ protected ChannelConnector createConnector(
SecurityPlan securityPlan,
Config config,
Clock clock,
RoutingContext routingContext) {
RoutingContext routingContext,
BoltAgent boltAgent) {
return new ChannelConnectorImpl(
settings,
securityPlan,
config.logging(),
clock,
routingContext,
getDomainNameResolver(),
config.notificationConfig());
config.notificationConfig(),
boltAgent);
}

private InternalDriver createDriver(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42;
import org.neo4j.driver.internal.messaging.v44.BoltProtocolV44;
import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
import org.neo4j.driver.internal.messaging.v52.BoltProtocolV52;
import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53;

public final class BoltProtocolUtil {
public static final int BOLT_MAGIC_PREAMBLE = 0x6060B017;
Expand All @@ -41,7 +41,7 @@ public final class BoltProtocolUtil {

private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer(copyInt(
BOLT_MAGIC_PREAMBLE,
BoltProtocolV52.VERSION.toIntRange(BoltProtocolV5.VERSION),
BoltProtocolV53.VERSION.toIntRange(BoltProtocolV5.VERSION),
BoltProtocolV44.VERSION.toIntRange(BoltProtocolV42.VERSION),
BoltProtocolV41.VERSION.toInt(),
BoltProtocolV3.VERSION.toInt()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.Logging;
import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.ConnectionSettings;
import org.neo4j.driver.internal.DomainNameResolver;
Expand All @@ -42,6 +43,7 @@

public class ChannelConnectorImpl implements ChannelConnector {
private final String userAgent;
private final BoltAgent boltAgent;
private final AuthTokenManager authTokenManager;
private final RoutingContext routingContext;
private final SecurityPlan securityPlan;
Expand All @@ -60,7 +62,8 @@ public ChannelConnectorImpl(
Clock clock,
RoutingContext routingContext,
DomainNameResolver domainNameResolver,
NotificationConfig notificationConfig) {
NotificationConfig notificationConfig,
BoltAgent boltAgent) {
this(
connectionSettings,
securityPlan,
Expand All @@ -69,7 +72,8 @@ public ChannelConnectorImpl(
clock,
routingContext,
domainNameResolver,
notificationConfig);
notificationConfig,
boltAgent);
}

public ChannelConnectorImpl(
Expand All @@ -80,8 +84,10 @@ public ChannelConnectorImpl(
Clock clock,
RoutingContext routingContext,
DomainNameResolver domainNameResolver,
NotificationConfig notificationConfig) {
NotificationConfig notificationConfig,
BoltAgent boltAgent) {
this.userAgent = connectionSettings.userAgent();
this.boltAgent = requireNonNull(boltAgent);
this.authTokenManager = connectionSettings.authTokenProvider();
this.routingContext = routingContext;
this.connectTimeoutMillis = connectionSettings.connectTimeoutMillis();
Expand Down Expand Up @@ -145,6 +151,6 @@ private void installHandshakeCompletedListeners(
// add listener that sends an INIT message. connection is now fully established. channel pipeline if fully
// set to send/receive messages for a selected protocol version
handshakeCompleted.addListener(new HandshakeCompletedListener(
userAgent, routingContext, connectionInitialized, notificationConfig, clock));
userAgent, boltAgent, routingContext, connectionInitialized, notificationConfig, clock));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,29 @@
import io.netty.channel.ChannelPromise;
import java.time.Clock;
import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.messaging.v51.BoltProtocolV51;

public class HandshakeCompletedListener implements ChannelFutureListener {
private final String userAgent;
private final BoltAgent boltAgent;
private final RoutingContext routingContext;
private final ChannelPromise connectionInitializedPromise;
private final NotificationConfig notificationConfig;
private final Clock clock;

public HandshakeCompletedListener(
String userAgent,
BoltAgent boltAgent,
RoutingContext routingContext,
ChannelPromise connectionInitializedPromise,
NotificationConfig notificationConfig,
Clock clock) {
requireNonNull(clock, "clock must not be null");
this.userAgent = requireNonNull(userAgent);
this.boltAgent = requireNonNull(boltAgent);
this.routingContext = routingContext;
this.connectionInitializedPromise = requireNonNull(connectionInitializedPromise);
this.notificationConfig = notificationConfig;
Expand All @@ -71,6 +75,7 @@ public void operationComplete(ChannelFuture future) {
authContext.setValidToken(authToken);
protocol.initializeChannel(
userAgent,
boltAgent,
authToken,
routingContext,
connectionInitializedPromise,
Expand All @@ -81,7 +86,13 @@ public void operationComplete(ChannelFuture future) {
channel.eventLoop());
} else {
protocol.initializeChannel(
userAgent, null, routingContext, connectionInitializedPromise, notificationConfig, clock);
userAgent,
boltAgent,
null,
routingContext,
connectionInitializedPromise,
notificationConfig,
clock);
}
} else {
connectionInitializedPromise.setFailure(future.cause());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.neo4j.driver.Transaction;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.DatabaseBookmark;
import org.neo4j.driver.internal.async.UnmanagedTransaction;
import org.neo4j.driver.internal.cluster.RoutingContext;
Expand All @@ -47,6 +48,7 @@
import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
import org.neo4j.driver.internal.messaging.v51.BoltProtocolV51;
import org.neo4j.driver.internal.messaging.v52.BoltProtocolV52;
import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53;
import org.neo4j.driver.internal.spi.Connection;

public interface BoltProtocol {
Expand All @@ -61,14 +63,16 @@ public interface BoltProtocol {
* Initialize channel after it is connected and handshake selected this protocol version.
*
* @param userAgent the user agent string.
* @param boltAgent the bolt agent
* @param authToken the authentication token.
* @param routingContext the configured routing context
* @param channelInitializedPromise the promise to be notified when initialization is completed.
* @param notificationConfig the notification configuration
* @param clock the clock to use
* @param notificationConfig the notification configuration
* @param clock the clock to use
*/
void initializeChannel(
String userAgent,
BoltAgent boltAgent,
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
Expand Down Expand Up @@ -189,6 +193,8 @@ static BoltProtocol forVersion(BoltProtocolVersion version) {
return BoltProtocolV51.INSTANCE;
} else if (BoltProtocolV52.VERSION.equals(version)) {
return BoltProtocolV52.INSTANCE;
} else if (BoltProtocolV53.VERSION.equals(version)) {
return BoltProtocolV53.INSTANCE;
}
throw new ClientException("Unknown protocol version: " + version);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,30 @@
import java.util.Objects;
import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.BoltAgent;

public class HelloMessage extends MessageWithMetadata {
public static final byte SIGNATURE = 0x01;

private static final String USER_AGENT_METADATA_KEY = "user_agent";
private static final String BOLT_AGENT_METADATA_KEY = "bolt_agent";
private static final String BOLT_AGENT_PRODUCT_KEY = "product";
private static final String BOLT_AGENT_PLATFORM_KEY = "platform";
private static final String BOLT_AGENT_LANGUAGE_KEY = "language";
private static final String BOLT_AGENT_LANGUAGE_DETAIL_KEY = "language_details";
private static final String ROUTING_CONTEXT_METADATA_KEY = "routing";
private static final String PATCH_BOLT_METADATA_KEY = "patch_bolt";

private static final String DATE_TIME_UTC_PATCH_VALUE = "utc";

public HelloMessage(
String userAgent,
BoltAgent boltAgent,
Map<String, Value> authToken,
Map<String, String> routingContext,
boolean includeDateTimeUtc,
NotificationConfig notificationConfig) {
super(buildMetadata(userAgent, authToken, routingContext, includeDateTimeUtc, notificationConfig));
super(buildMetadata(userAgent, boltAgent, authToken, routingContext, includeDateTimeUtc, notificationConfig));
}

@Override
Expand Down Expand Up @@ -77,12 +84,29 @@ public String toString() {

private static Map<String, Value> buildMetadata(
String userAgent,
BoltAgent boltAgent,
Map<String, Value> authToken,
Map<String, String> routingContext,
boolean includeDateTimeUtc,
NotificationConfig notificationConfig) {
Map<String, Value> result = new HashMap<>(authToken);
result.put(USER_AGENT_METADATA_KEY, value(userAgent));
if (userAgent != null) {
result.put(USER_AGENT_METADATA_KEY, value(userAgent));
}
if (boltAgent != null) {
var boltAgentMap = new HashMap<String, String>();
boltAgentMap.put(BOLT_AGENT_PRODUCT_KEY, boltAgent.product());
if (boltAgent.platform() != null) {
boltAgentMap.put(BOLT_AGENT_PLATFORM_KEY, boltAgent.platform());
}
if (boltAgent.language() != null) {
boltAgentMap.put(BOLT_AGENT_LANGUAGE_KEY, boltAgent.language());
}
if (boltAgent.languageDetails() != null) {
boltAgentMap.put(BOLT_AGENT_LANGUAGE_DETAIL_KEY, boltAgent.languageDetails());
}
result.put(BOLT_AGENT_METADATA_KEY, value(boltAgentMap));
}
if (routingContext != null) {
result.put(ROUTING_CONTEXT_METADATA_KEY, value(routingContext));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.exceptions.Neo4jException;
import org.neo4j.driver.exceptions.UnsupportedFeatureException;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.DatabaseBookmark;
import org.neo4j.driver.internal.DatabaseName;
import org.neo4j.driver.internal.async.UnmanagedTransaction;
Expand Down Expand Up @@ -81,6 +82,7 @@ public MessageFormat createMessageFormat() {
@Override
public void initializeChannel(
String userAgent,
BoltAgent boltAgent,
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
Expand All @@ -97,13 +99,15 @@ public void initializeChannel(
if (routingContext.isServerRoutingEnabled()) {
message = new HelloMessage(
userAgent,
null,
((InternalAuthToken) authToken).toMap(),
routingContext.toMap(),
includeDateTimeUtcPatchInHello(),
notificationConfig);
} else {
message = new HelloMessage(
userAgent,
null,
((InternalAuthToken) authToken).toMap(),
null,
includeDateTimeUtcPatchInHello(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.concurrent.CompletableFuture;
import org.neo4j.driver.AuthToken;
import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.handlers.HelloV51ResponseHandler;
import org.neo4j.driver.internal.messaging.BoltProtocol;
Expand All @@ -42,6 +43,7 @@ public class BoltProtocolV51 extends BoltProtocolV5 {
@Override
public void initializeChannel(
String userAgent,
BoltAgent boltAgent,
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
Expand All @@ -57,9 +59,9 @@ public void initializeChannel(

if (routingContext.isServerRoutingEnabled()) {
message = new HelloMessage(
userAgent, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
userAgent, null, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
} else {
message = new HelloMessage(userAgent, Collections.emptyMap(), null, false, notificationConfig);
message = new HelloMessage(userAgent, null, Collections.emptyMap(), null, false, notificationConfig);
}

var helloFuture = new CompletableFuture<Void>();
Expand Down
Loading