Skip to content

Commit 56ecf3f

Browse files
authored
Update internal Bolt exception structure (#1590)
The main goal of this update is to refactor internal Bolt exception handling and to separate it from the user facing exceptions.
1 parent c84ca38 commit 56ecf3f

File tree

102 files changed

+2442
-914
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+2442
-914
lines changed

driver/src/main/java/org/neo4j/driver/exceptions/Neo4jException.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ public Optional<Neo4jException> gqlCause() {
238238
return findFirstGqlCause(this, Neo4jException.class);
239239
}
240240

241+
@SuppressWarnings("DuplicatedCode")
241242
private static <T extends Throwable> Optional<T> findFirstGqlCause(Throwable throwable, Class<T> targetCls) {
242243
var cause = throwable.getCause();
243244
if (cause == null) {

driver/src/main/java/org/neo4j/driver/exceptions/SecurityRetryableException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* Indicates that the contained {@link SecurityException} is a {@link RetryableException}, which is determined by the
2626
* {@link org.neo4j.driver.AuthTokenManager#handleSecurityException(AuthToken, SecurityException)} method.
2727
* <p>
28-
* The original {@link java.lang.SecurityException} is always available as a {@link Throwable#getCause()}. The
28+
* The original {@link SecurityException} is always available as a {@link Throwable#getCause()}. The
2929
* {@link SecurityRetryableException#code()} and {@link SecurityRetryableException#getMessage()} supply the values from
3030
* the original exception.
3131
*

driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
import org.neo4j.driver.Driver;
4040
import org.neo4j.driver.Logging;
4141
import org.neo4j.driver.MetricsAdapter;
42+
import org.neo4j.driver.internal.adaptedbolt.AdaptingDriverBoltConnectionProvider;
43+
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnectionProvider;
44+
import org.neo4j.driver.internal.adaptedbolt.ErrorMapper;
4245
import org.neo4j.driver.internal.bolt.api.BoltConnectionProvider;
4346
import org.neo4j.driver.internal.bolt.api.BoltServerAddress;
4447
import org.neo4j.driver.internal.bolt.api.DefaultDomainNameResolver;
@@ -158,7 +161,7 @@ private InternalDriver createDriver(
158161
AuthTokenManager authTokenManager,
159162
boolean ownsEventLoopGroup,
160163
Supplier<Rediscovery> rediscoverySupplier) {
161-
BoltConnectionProvider boltConnectionProvider = null;
164+
DriverBoltConnectionProvider boltConnectionProvider = null;
162165
try {
163166
boltConnectionProvider =
164167
createBoltConnectionProvider(uri, config, eventLoopGroup, routingSettings, rediscoverySupplier);
@@ -204,28 +207,33 @@ private Function<BoltServerAddress, Set<BoltServerAddress>> createBoltServerAddr
204207
.collect(Collectors.toCollection(LinkedHashSet::new));
205208
}
206209

207-
private BoltConnectionProvider createBoltConnectionProvider(
210+
private DriverBoltConnectionProvider createBoltConnectionProvider(
208211
URI uri,
209212
Config config,
210213
EventLoopGroup eventLoopGroup,
211214
RoutingSettings routingSettings,
212215
Supplier<Rediscovery> rediscoverySupplier) {
213-
BoltConnectionProvider boltConnectionProvider;
216+
DriverBoltConnectionProvider boltConnectionProvider;
214217
var clock = createClock();
215218
var loggingProvider = new BoltLoggingProvider(config.logging());
216219
Supplier<BoltConnectionProvider> pooledBoltConnectionProviderSupplier =
217220
() -> createPooledBoltConnectionProvider(config, eventLoopGroup, clock, loggingProvider);
221+
var errorMapper = ErrorMapper.getInstance();
218222
if (uri.getScheme().startsWith("bolt")) {
219223
assertNoRoutingContext(uri, routingSettings);
220-
boltConnectionProvider = pooledBoltConnectionProviderSupplier.get();
224+
boltConnectionProvider = new AdaptingDriverBoltConnectionProvider(
225+
pooledBoltConnectionProviderSupplier.get(), errorMapper, false);
221226
} else {
222-
boltConnectionProvider = createRoutedBoltConnectionProvider(
223-
config,
224-
pooledBoltConnectionProviderSupplier,
225-
routingSettings,
226-
rediscoverySupplier,
227-
clock,
228-
loggingProvider);
227+
boltConnectionProvider = new AdaptingDriverBoltConnectionProvider(
228+
createRoutedBoltConnectionProvider(
229+
config,
230+
pooledBoltConnectionProviderSupplier,
231+
routingSettings,
232+
rediscoverySupplier,
233+
clock,
234+
loggingProvider),
235+
errorMapper,
236+
true);
229237
}
230238
return boltConnectionProvider;
231239
}
@@ -308,7 +316,7 @@ protected Clock createClock() {
308316
*/
309317
protected SessionFactory createSessionFactory(
310318
BoltSecurityPlanManager securityPlanManager,
311-
BoltConnectionProvider connectionProvider,
319+
DriverBoltConnectionProvider connectionProvider,
312320
RetryLogic retryLogic,
313321
Config config,
314322
AuthTokenManager authTokenManager) {

driver/src/main/java/org/neo4j/driver/internal/InternalResult.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@
2828
import org.neo4j.driver.async.ResultCursor;
2929
import org.neo4j.driver.exceptions.ClientException;
3030
import org.neo4j.driver.exceptions.NoSuchRecordException;
31-
import org.neo4j.driver.internal.bolt.api.BoltConnection;
31+
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection;
3232
import org.neo4j.driver.internal.bolt.api.GqlStatusError;
3333
import org.neo4j.driver.internal.util.Futures;
3434
import org.neo4j.driver.summary.ResultSummary;
3535

3636
public class InternalResult implements Result {
37-
private final BoltConnection connection;
37+
private final DriverBoltConnection connection;
3838
private final ResultCursor cursor;
3939

40-
public InternalResult(BoltConnection connection, ResultCursor cursor) {
40+
public InternalResult(DriverBoltConnection connection, ResultCursor cursor) {
4141
this.connection = connection;
4242
this.cursor = cursor;
4343
}

driver/src/main/java/org/neo4j/driver/internal/InternalSession.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
import org.neo4j.driver.TransactionConfig;
3131
import org.neo4j.driver.TransactionWork;
3232
import org.neo4j.driver.exceptions.ClientException;
33+
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection;
3334
import org.neo4j.driver.internal.async.NetworkSession;
34-
import org.neo4j.driver.internal.bolt.api.BoltConnection;
3535
import org.neo4j.driver.internal.bolt.api.GqlStatusError;
3636
import org.neo4j.driver.internal.bolt.api.TelemetryApi;
3737
import org.neo4j.driver.internal.telemetry.ApiTelemetryWork;
@@ -208,7 +208,7 @@ private Transaction beginTransaction(
208208

209209
private void terminateConnectionOnThreadInterrupt(String reason) {
210210
// try to get current connection if it has been acquired
211-
BoltConnection connection = null;
211+
DriverBoltConnection connection = null;
212212
try {
213213
connection = Futures.getNow(session.connectionAsync());
214214
} catch (Throwable ignore) {

driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
import org.neo4j.driver.NotificationConfig;
3434
import org.neo4j.driver.SessionConfig;
3535
import org.neo4j.driver.Value;
36+
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnectionProvider;
3637
import org.neo4j.driver.internal.async.LeakLoggingNetworkSession;
3738
import org.neo4j.driver.internal.async.NetworkSession;
38-
import org.neo4j.driver.internal.bolt.api.BoltConnectionProvider;
3939
import org.neo4j.driver.internal.bolt.api.DatabaseName;
4040
import org.neo4j.driver.internal.bolt.api.DatabaseNameUtil;
4141
import org.neo4j.driver.internal.bolt.api.SecurityPlan;
@@ -45,7 +45,7 @@
4545

4646
public class SessionFactoryImpl implements SessionFactory {
4747
private final BoltSecurityPlanManager securityPlanManager;
48-
private final BoltConnectionProvider connectionProvider;
48+
private final DriverBoltConnectionProvider connectionProvider;
4949
private final RetryLogic retryLogic;
5050
private final Logging logging;
5151
private final boolean leakedSessionsLoggingEnabled;
@@ -54,7 +54,7 @@ public class SessionFactoryImpl implements SessionFactory {
5454

5555
SessionFactoryImpl(
5656
BoltSecurityPlanManager securityPlanManager,
57-
BoltConnectionProvider connectionProvider,
57+
DriverBoltConnectionProvider connectionProvider,
5858
RetryLogic retryLogic,
5959
Config config,
6060
AuthTokenManager authTokenManager) {
@@ -163,7 +163,7 @@ public CompletionStage<Boolean> supportsSessionAuth() {
163163

164164
private NetworkSession createSession(
165165
BoltSecurityPlanManager securityPlanManager,
166-
BoltConnectionProvider connectionProvider,
166+
DriverBoltConnectionProvider connectionProvider,
167167
RetryLogic retryLogic,
168168
DatabaseName databaseName,
169169
AccessMode mode,
@@ -214,7 +214,7 @@ private NetworkSession createSession(
214214
authTokenManager);
215215
}
216216

217-
public BoltConnectionProvider getConnectionProvider() {
217+
public DriverBoltConnectionProvider getConnectionProvider() {
218218
return connectionProvider;
219219
}
220220

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal.adaptedbolt;
18+
19+
import java.time.Duration;
20+
import java.util.Map;
21+
import java.util.Objects;
22+
import java.util.Set;
23+
import java.util.concurrent.CompletionStage;
24+
import org.neo4j.driver.Value;
25+
import org.neo4j.driver.internal.bolt.api.AccessMode;
26+
import org.neo4j.driver.internal.bolt.api.AuthData;
27+
import org.neo4j.driver.internal.bolt.api.BoltConnection;
28+
import org.neo4j.driver.internal.bolt.api.BoltConnectionState;
29+
import org.neo4j.driver.internal.bolt.api.BoltProtocolVersion;
30+
import org.neo4j.driver.internal.bolt.api.BoltServerAddress;
31+
import org.neo4j.driver.internal.bolt.api.DatabaseName;
32+
import org.neo4j.driver.internal.bolt.api.NotificationConfig;
33+
import org.neo4j.driver.internal.bolt.api.TelemetryApi;
34+
import org.neo4j.driver.internal.bolt.api.TransactionType;
35+
36+
final class AdaptingDriverBoltConnection implements DriverBoltConnection {
37+
private final BoltConnection connection;
38+
private final ErrorMapper errorMapper;
39+
40+
AdaptingDriverBoltConnection(BoltConnection connection, ErrorMapper errorMapper) {
41+
this.connection = Objects.requireNonNull(connection);
42+
this.errorMapper = Objects.requireNonNull(errorMapper);
43+
}
44+
45+
@Override
46+
public CompletionStage<DriverBoltConnection> onLoop() {
47+
return connection.onLoop().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
48+
}
49+
50+
@Override
51+
public CompletionStage<DriverBoltConnection> route(
52+
DatabaseName databaseName, String impersonatedUser, Set<String> bookmarks) {
53+
return connection
54+
.route(databaseName, impersonatedUser, bookmarks)
55+
.exceptionally(errorMapper::mapAndTrow)
56+
.thenApply(ignored -> this);
57+
}
58+
59+
@Override
60+
public CompletionStage<DriverBoltConnection> beginTransaction(
61+
DatabaseName databaseName,
62+
AccessMode accessMode,
63+
String impersonatedUser,
64+
Set<String> bookmarks,
65+
TransactionType transactionType,
66+
Duration txTimeout,
67+
Map<String, Value> txMetadata,
68+
String txType,
69+
NotificationConfig notificationConfig) {
70+
return connection
71+
.beginTransaction(
72+
databaseName,
73+
accessMode,
74+
impersonatedUser,
75+
bookmarks,
76+
transactionType,
77+
txTimeout,
78+
txMetadata,
79+
txType,
80+
notificationConfig)
81+
.exceptionally(errorMapper::mapAndTrow)
82+
.thenApply(ignored -> this);
83+
}
84+
85+
@Override
86+
public CompletionStage<DriverBoltConnection> runInAutoCommitTransaction(
87+
DatabaseName databaseName,
88+
AccessMode accessMode,
89+
String impersonatedUser,
90+
Set<String> bookmarks,
91+
String query,
92+
Map<String, Value> parameters,
93+
Duration txTimeout,
94+
Map<String, Value> txMetadata,
95+
NotificationConfig notificationConfig) {
96+
return connection
97+
.runInAutoCommitTransaction(
98+
databaseName,
99+
accessMode,
100+
impersonatedUser,
101+
bookmarks,
102+
query,
103+
parameters,
104+
txTimeout,
105+
txMetadata,
106+
notificationConfig)
107+
.exceptionally(errorMapper::mapAndTrow)
108+
.thenApply(ignored -> this);
109+
}
110+
111+
@Override
112+
public CompletionStage<DriverBoltConnection> run(String query, Map<String, Value> parameters) {
113+
return connection
114+
.run(query, parameters)
115+
.exceptionally(errorMapper::mapAndTrow)
116+
.thenApply(ignored -> this);
117+
}
118+
119+
@Override
120+
public CompletionStage<DriverBoltConnection> pull(long qid, long request) {
121+
return connection
122+
.pull(qid, request)
123+
.exceptionally(errorMapper::mapAndTrow)
124+
.thenApply(ignored -> this);
125+
}
126+
127+
@Override
128+
public CompletionStage<DriverBoltConnection> discard(long qid, long number) {
129+
return connection
130+
.discard(qid, number)
131+
.exceptionally(errorMapper::mapAndTrow)
132+
.thenApply(ignored -> this);
133+
}
134+
135+
@Override
136+
public CompletionStage<DriverBoltConnection> commit() {
137+
return connection.commit().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
138+
}
139+
140+
@Override
141+
public CompletionStage<DriverBoltConnection> rollback() {
142+
return connection.rollback().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
143+
}
144+
145+
@Override
146+
public CompletionStage<DriverBoltConnection> reset() {
147+
return connection.reset().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
148+
}
149+
150+
@Override
151+
public CompletionStage<DriverBoltConnection> logoff() {
152+
return connection.logoff().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
153+
}
154+
155+
@Override
156+
public CompletionStage<DriverBoltConnection> logon(Map<String, Value> authMap) {
157+
return connection.logon(authMap).exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
158+
}
159+
160+
@Override
161+
public CompletionStage<DriverBoltConnection> telemetry(TelemetryApi telemetryApi) {
162+
return connection
163+
.telemetry(telemetryApi)
164+
.exceptionally(errorMapper::mapAndTrow)
165+
.thenApply(ignored -> this);
166+
}
167+
168+
@Override
169+
public CompletionStage<DriverBoltConnection> clear() {
170+
return connection.clear().exceptionally(errorMapper::mapAndTrow).thenApply(ignored -> this);
171+
}
172+
173+
@Override
174+
public CompletionStage<Void> flush(DriverResponseHandler handler) {
175+
return connection
176+
.flush(new AdaptingDriverResponseHandler(handler, errorMapper))
177+
.exceptionally(errorMapper::mapAndTrow);
178+
}
179+
180+
@Override
181+
public CompletionStage<Void> forceClose(String reason) {
182+
return connection.forceClose(reason).exceptionally(errorMapper::mapAndTrow);
183+
}
184+
185+
@Override
186+
public CompletionStage<Void> close() {
187+
return connection.close().exceptionally(errorMapper::mapAndTrow);
188+
}
189+
190+
@Override
191+
public BoltConnectionState state() {
192+
return connection.state();
193+
}
194+
195+
@Override
196+
public CompletionStage<AuthData> authData() {
197+
return connection.authData().exceptionally(errorMapper::mapAndTrow);
198+
}
199+
200+
@Override
201+
public String serverAgent() {
202+
return connection.serverAgent();
203+
}
204+
205+
@Override
206+
public BoltServerAddress serverAddress() {
207+
return connection.serverAddress();
208+
}
209+
210+
@Override
211+
public BoltProtocolVersion protocolVersion() {
212+
return connection.protocolVersion();
213+
}
214+
215+
@Override
216+
public boolean telemetrySupported() {
217+
return connection.telemetrySupported();
218+
}
219+
}

0 commit comments

Comments
 (0)