Skip to content

Update internal Bolt exception structure #1590

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 1 commit into from
Dec 3, 2024
Merged
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
Expand Up @@ -238,6 +238,7 @@ public Optional<Neo4jException> gqlCause() {
return findFirstGqlCause(this, Neo4jException.class);
}

@SuppressWarnings("DuplicatedCode")
private static <T extends Throwable> Optional<T> findFirstGqlCause(Throwable throwable, Class<T> targetCls) {
var cause = throwable.getCause();
if (cause == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* Indicates that the contained {@link SecurityException} is a {@link RetryableException}, which is determined by the
* {@link org.neo4j.driver.AuthTokenManager#handleSecurityException(AuthToken, SecurityException)} method.
* <p>
* The original {@link java.lang.SecurityException} is always available as a {@link Throwable#getCause()}. The
* The original {@link SecurityException} is always available as a {@link Throwable#getCause()}. The
* {@link SecurityRetryableException#code()} and {@link SecurityRetryableException#getMessage()} supply the values from
* the original exception.
*
Expand Down
32 changes: 20 additions & 12 deletions driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import org.neo4j.driver.Driver;
import org.neo4j.driver.Logging;
import org.neo4j.driver.MetricsAdapter;
import org.neo4j.driver.internal.adaptedbolt.AdaptingDriverBoltConnectionProvider;
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnectionProvider;
import org.neo4j.driver.internal.adaptedbolt.ErrorMapper;
import org.neo4j.driver.internal.bolt.api.BoltConnectionProvider;
import org.neo4j.driver.internal.bolt.api.BoltServerAddress;
import org.neo4j.driver.internal.bolt.api.DefaultDomainNameResolver;
Expand Down Expand Up @@ -158,7 +161,7 @@ private InternalDriver createDriver(
AuthTokenManager authTokenManager,
boolean ownsEventLoopGroup,
Supplier<Rediscovery> rediscoverySupplier) {
BoltConnectionProvider boltConnectionProvider = null;
DriverBoltConnectionProvider boltConnectionProvider = null;
try {
boltConnectionProvider =
createBoltConnectionProvider(uri, config, eventLoopGroup, routingSettings, rediscoverySupplier);
Expand Down Expand Up @@ -204,28 +207,33 @@ private Function<BoltServerAddress, Set<BoltServerAddress>> createBoltServerAddr
.collect(Collectors.toCollection(LinkedHashSet::new));
}

private BoltConnectionProvider createBoltConnectionProvider(
private DriverBoltConnectionProvider createBoltConnectionProvider(
URI uri,
Config config,
EventLoopGroup eventLoopGroup,
RoutingSettings routingSettings,
Supplier<Rediscovery> rediscoverySupplier) {
BoltConnectionProvider boltConnectionProvider;
DriverBoltConnectionProvider boltConnectionProvider;
var clock = createClock();
var loggingProvider = new BoltLoggingProvider(config.logging());
Supplier<BoltConnectionProvider> pooledBoltConnectionProviderSupplier =
() -> createPooledBoltConnectionProvider(config, eventLoopGroup, clock, loggingProvider);
var errorMapper = ErrorMapper.getInstance();
if (uri.getScheme().startsWith("bolt")) {
assertNoRoutingContext(uri, routingSettings);
boltConnectionProvider = pooledBoltConnectionProviderSupplier.get();
boltConnectionProvider = new AdaptingDriverBoltConnectionProvider(
pooledBoltConnectionProviderSupplier.get(), errorMapper, false);
} else {
boltConnectionProvider = createRoutedBoltConnectionProvider(
config,
pooledBoltConnectionProviderSupplier,
routingSettings,
rediscoverySupplier,
clock,
loggingProvider);
boltConnectionProvider = new AdaptingDriverBoltConnectionProvider(
createRoutedBoltConnectionProvider(
config,
pooledBoltConnectionProviderSupplier,
routingSettings,
rediscoverySupplier,
clock,
loggingProvider),
errorMapper,
true);
}
return boltConnectionProvider;
}
Expand Down Expand Up @@ -308,7 +316,7 @@ protected Clock createClock() {
*/
protected SessionFactory createSessionFactory(
BoltSecurityPlanManager securityPlanManager,
BoltConnectionProvider connectionProvider,
DriverBoltConnectionProvider connectionProvider,
RetryLogic retryLogic,
Config config,
AuthTokenManager authTokenManager) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@
import org.neo4j.driver.async.ResultCursor;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.exceptions.NoSuchRecordException;
import org.neo4j.driver.internal.bolt.api.BoltConnection;
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection;
import org.neo4j.driver.internal.bolt.api.GqlStatusError;
import org.neo4j.driver.internal.util.Futures;
import org.neo4j.driver.summary.ResultSummary;

public class InternalResult implements Result {
private final BoltConnection connection;
private final DriverBoltConnection connection;
private final ResultCursor cursor;

public InternalResult(BoltConnection connection, ResultCursor cursor) {
public InternalResult(DriverBoltConnection connection, ResultCursor cursor) {
this.connection = connection;
this.cursor = cursor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.TransactionWork;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection;
import org.neo4j.driver.internal.async.NetworkSession;
import org.neo4j.driver.internal.bolt.api.BoltConnection;
import org.neo4j.driver.internal.bolt.api.GqlStatusError;
import org.neo4j.driver.internal.bolt.api.TelemetryApi;
import org.neo4j.driver.internal.telemetry.ApiTelemetryWork;
Expand Down Expand Up @@ -208,7 +208,7 @@ private Transaction beginTransaction(

private void terminateConnectionOnThreadInterrupt(String reason) {
// try to get current connection if it has been acquired
BoltConnection connection = null;
DriverBoltConnection connection = null;
try {
connection = Futures.getNow(session.connectionAsync());
} catch (Throwable ignore) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnectionProvider;
import org.neo4j.driver.internal.async.LeakLoggingNetworkSession;
import org.neo4j.driver.internal.async.NetworkSession;
import org.neo4j.driver.internal.bolt.api.BoltConnectionProvider;
import org.neo4j.driver.internal.bolt.api.DatabaseName;
import org.neo4j.driver.internal.bolt.api.DatabaseNameUtil;
import org.neo4j.driver.internal.bolt.api.SecurityPlan;
Expand All @@ -45,7 +45,7 @@

public class SessionFactoryImpl implements SessionFactory {
private final BoltSecurityPlanManager securityPlanManager;
private final BoltConnectionProvider connectionProvider;
private final DriverBoltConnectionProvider connectionProvider;
private final RetryLogic retryLogic;
private final Logging logging;
private final boolean leakedSessionsLoggingEnabled;
Expand All @@ -54,7 +54,7 @@ public class SessionFactoryImpl implements SessionFactory {

SessionFactoryImpl(
BoltSecurityPlanManager securityPlanManager,
BoltConnectionProvider connectionProvider,
DriverBoltConnectionProvider connectionProvider,
RetryLogic retryLogic,
Config config,
AuthTokenManager authTokenManager) {
Expand Down Expand Up @@ -163,7 +163,7 @@ public CompletionStage<Boolean> supportsSessionAuth() {

private NetworkSession createSession(
BoltSecurityPlanManager securityPlanManager,
BoltConnectionProvider connectionProvider,
DriverBoltConnectionProvider connectionProvider,
RetryLogic retryLogic,
DatabaseName databaseName,
AccessMode mode,
Expand Down Expand Up @@ -214,7 +214,7 @@ private NetworkSession createSession(
authTokenManager);
}

public BoltConnectionProvider getConnectionProvider() {
public DriverBoltConnectionProvider getConnectionProvider() {
return connectionProvider;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* 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.adaptedbolt;

import java.time.Duration;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletionStage;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.bolt.api.AccessMode;
import org.neo4j.driver.internal.bolt.api.AuthData;
import org.neo4j.driver.internal.bolt.api.BoltConnection;
import org.neo4j.driver.internal.bolt.api.BoltConnectionState;
import org.neo4j.driver.internal.bolt.api.BoltProtocolVersion;
import org.neo4j.driver.internal.bolt.api.BoltServerAddress;
import org.neo4j.driver.internal.bolt.api.DatabaseName;
import org.neo4j.driver.internal.bolt.api.NotificationConfig;
import org.neo4j.driver.internal.bolt.api.TelemetryApi;
import org.neo4j.driver.internal.bolt.api.TransactionType;

final class AdaptingDriverBoltConnection implements DriverBoltConnection {
private final BoltConnection connection;
private final ErrorMapper errorMapper;

AdaptingDriverBoltConnection(BoltConnection connection, ErrorMapper errorMapper) {
this.connection = Objects.requireNonNull(connection);
this.errorMapper = Objects.requireNonNull(errorMapper);
}

@Override
public CompletionStage<DriverBoltConnection> onLoop() {
return connection.onLoop().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> route(
DatabaseName databaseName, String impersonatedUser, Set<String> bookmarks) {
return connection
.route(databaseName, impersonatedUser, bookmarks)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> beginTransaction(
DatabaseName databaseName,
AccessMode accessMode,
String impersonatedUser,
Set<String> bookmarks,
TransactionType transactionType,
Duration txTimeout,
Map<String, Value> txMetadata,
String txType,
NotificationConfig notificationConfig) {
return connection
.beginTransaction(
databaseName,
accessMode,
impersonatedUser,
bookmarks,
transactionType,
txTimeout,
txMetadata,
txType,
notificationConfig)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> runInAutoCommitTransaction(
DatabaseName databaseName,
AccessMode accessMode,
String impersonatedUser,
Set<String> bookmarks,
String query,
Map<String, Value> parameters,
Duration txTimeout,
Map<String, Value> txMetadata,
NotificationConfig notificationConfig) {
return connection
.runInAutoCommitTransaction(
databaseName,
accessMode,
impersonatedUser,
bookmarks,
query,
parameters,
txTimeout,
txMetadata,
notificationConfig)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> run(String query, Map<String, Value> parameters) {
return connection
.run(query, parameters)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> pull(long qid, long request) {
return connection
.pull(qid, request)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> discard(long qid, long number) {
return connection
.discard(qid, number)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> commit() {
return connection.commit().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> rollback() {
return connection.rollback().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> reset() {
return connection.reset().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> logoff() {
return connection.logoff().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> logon(Map<String, Value> authMap) {
return connection.logon(authMap).exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> telemetry(TelemetryApi telemetryApi) {
return connection
.telemetry(telemetryApi)
.exceptionally(errorMapper::mapAndTrow)
.thenApply(ignored -> this);
}

@Override
public CompletionStage<DriverBoltConnection> clear() {
return connection.clear().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
}

@Override
public CompletionStage<Void> flush(DriverResponseHandler handler) {
return connection
.flush(new AdaptingDriverResponseHandler(handler, errorMapper))
.exceptionally(errorMapper::mapAndTrow);
}

@Override
public CompletionStage<Void> forceClose(String reason) {
return connection.forceClose(reason).exceptionally(errorMapper::mapAndTrow);
}

@Override
public CompletionStage<Void> close() {
return connection.close().exceptionally(errorMapper::mapAndTrow);
}

@Override
public BoltConnectionState state() {
return connection.state();
}

@Override
public CompletionStage<AuthData> authData() {
return connection.authData().exceptionally(errorMapper::mapAndTrow);
}

@Override
public String serverAgent() {
return connection.serverAgent();
}

@Override
public BoltServerAddress serverAddress() {
return connection.serverAddress();
}

@Override
public BoltProtocolVersion protocolVersion() {
return connection.protocolVersion();
}

@Override
public boolean telemetrySupported() {
return connection.telemetrySupported();
}
}
Loading