Skip to content

Commit a1d61cc

Browse files
committed
Throw exception when NotificationConfig is not supported
This update introduces a new `UnsupportedFeatureException`. An instance of this exception will be emitted if `NotificationConfig` is enabled and driver comes across a Bolt connection that does not support it. The exception may be used for other similar cases in the future as well.
1 parent 848107c commit a1d61cc

File tree

8 files changed

+112
-17
lines changed

8 files changed

+112
-17
lines changed

driver/src/main/java/org/neo4j/driver/Config.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Objects;
3333
import java.util.concurrent.TimeUnit;
3434
import java.util.logging.Level;
35+
import org.neo4j.driver.exceptions.UnsupportedFeatureException;
3536
import org.neo4j.driver.internal.SecuritySettings;
3637
import org.neo4j.driver.internal.async.pool.PoolSettings;
3738
import org.neo4j.driver.internal.cluster.RoutingSettings;
@@ -775,7 +776,10 @@ public ConfigBuilder withUserAgent(String userAgent) {
775776
/**
776777
* Sets notification config.
777778
* <p>
778-
* This configuration is supported over Bolt protocol version 5.2 and above.
779+
* Any configuration other than the {@link NotificationConfig#defaultConfig()} requires a minimum Bolt protocol
780+
* version 5.2. Otherwise, an {@link UnsupportedFeatureException} will be emitted when driver comes across a
781+
* Bolt connection that does not support this feature. For instance, when running a query.
782+
*
779783
* @param notificationConfig the notification config
780784
* @return this builder
781785
* @since 5.7

driver/src/main/java/org/neo4j/driver/NotificationConfig.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,31 @@
2222
import java.util.Set;
2323
import org.neo4j.driver.internal.InternalNotificationConfig;
2424
import org.neo4j.driver.internal.InternalNotificationSeverity;
25+
import org.neo4j.driver.summary.ResultSummary;
2526

2627
/**
27-
* Notification configuration that defines what notifications the server should supply to the driver.
28+
* A notification configuration defining what notifications should be supplied by the server.
2829
* <p>
29-
* This configuration is only supported over Bolt protocol version 5.2 and above. It is effectively ignored on the previous versions.
30+
* There are currently 2 optional settings that may be activated:
31+
* <ul>
32+
* <li>Minimum notification severity - sets a baseline severity for notifications, similar to the logging levels.</li>
33+
* <li>A set of disabled notification categories - explicitly disables a set of notification categories.</li>
34+
* </ul>
35+
* <p>
36+
* By default, both options are not activated.
3037
*
3138
* @since 5.7
39+
* @see ResultSummary#notifications()
40+
* @see org.neo4j.driver.summary.Notification
3241
*/
3342
public sealed interface NotificationConfig extends Serializable permits InternalNotificationConfig {
3443
/**
35-
* Returns a default notification config.
44+
* Returns a default notification configuration.
3645
* <p>
37-
* It has no options activated, meaning the resulting behaviour depends on an upstream entity. For instance,
38-
* when this config is set on the session level, the resulting behaviour depends on the driver's config.
39-
* Likewise, when this config is set on the driver level, the resulting behaviour depends on the server.
46+
* The default configuration has no settings activated, meaning the resulting behaviour depends on an upstream
47+
* context. For instance, when this config is set on the session level, the resulting behaviour depends on the
48+
* driver's config. Likewise, when this config is set on the driver level, the resulting behaviour depends on the
49+
* server.
4050
*
4151
* @return the default config
4252
*/
@@ -49,7 +59,7 @@ static NotificationConfig defaultConfig() {
4959
*
5060
* @return the config that disables all notifications
5161
*/
52-
static NotificationConfig disableAll() {
62+
static NotificationConfig disableAllConfig() {
5363
return new InternalNotificationConfig(InternalNotificationSeverity.OFF, null);
5464
}
5565

driver/src/main/java/org/neo4j/driver/SessionConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Objects;
2828
import java.util.Optional;
2929
import org.neo4j.driver.async.AsyncSession;
30+
import org.neo4j.driver.exceptions.UnsupportedFeatureException;
3031
import org.neo4j.driver.reactive.ReactiveSession;
3132
import org.neo4j.driver.reactive.RxSession;
3233
import org.neo4j.driver.util.Experimental;
@@ -385,7 +386,10 @@ public Builder withBookmarkManager(BookmarkManager bookmarkManager) {
385386
/**
386387
* Sets notification config.
387388
* <p>
388-
* This configuration is supported over Bolt protocol version 5.2 and above.
389+
* Any configuration other than the {@link NotificationConfig#defaultConfig()} requires a minimum Bolt protocol
390+
* version 5.2. Otherwise, an {@link UnsupportedFeatureException} will be emitted when driver comes across a
391+
* Bolt connection that does not support this feature. For instance, when running a query.
392+
*
389393
* @param notificationConfig the notification config
390394
* @return this builder
391395
* @since 5.7
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.exceptions;
20+
21+
import java.io.Serial;
22+
23+
/**
24+
* A feature is not supported in a given setup.
25+
* @since 5.7
26+
*/
27+
public class UnsupportedFeatureException extends ClientException {
28+
@Serial
29+
private static final long serialVersionUID = 1161333003602398544L;
30+
31+
/**
32+
* Constructs a new instance.
33+
* @param message the message
34+
*/
35+
public UnsupportedFeatureException(String message) {
36+
super(message);
37+
}
38+
39+
/**
40+
* Constructs a new instance.
41+
* @param message the message
42+
* @param cause the cause
43+
*/
44+
public UnsupportedFeatureException(String message, Throwable cause) {
45+
super(message, cause);
46+
}
47+
}

driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.neo4j.driver.exceptions.FatalDiscoveryException;
4444
import org.neo4j.driver.exceptions.SecurityException;
4545
import org.neo4j.driver.exceptions.ServiceUnavailableException;
46+
import org.neo4j.driver.exceptions.UnsupportedFeatureException;
4647
import org.neo4j.driver.internal.BoltServerAddress;
4748
import org.neo4j.driver.internal.DomainNameResolver;
4849
import org.neo4j.driver.internal.ImpersonationUtil;
@@ -296,6 +297,8 @@ private boolean mustAbortDiscovery(Throwable throwable) {
296297
} else if (throwable instanceof IllegalStateException
297298
&& ConnectionPool.CONNECTION_POOL_CLOSED_ERROR_MESSAGE.equals(throwable.getMessage())) {
298299
abort = true;
300+
} else if (throwable instanceof UnsupportedFeatureException) {
301+
abort = true;
299302
} else if (throwable instanceof ClientException) {
300303
String code = ((ClientException) throwable).code();
301304
abort = switch (code) {

driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import org.neo4j.driver.NotificationConfig;
3838
import org.neo4j.driver.Query;
3939
import org.neo4j.driver.TransactionConfig;
40+
import org.neo4j.driver.exceptions.Neo4jException;
41+
import org.neo4j.driver.exceptions.UnsupportedFeatureException;
4042
import org.neo4j.driver.internal.DatabaseBookmark;
4143
import org.neo4j.driver.internal.DatabaseName;
4244
import org.neo4j.driver.internal.async.UnmanagedTransaction;
@@ -82,6 +84,11 @@ public void initializeChannel(
8284
RoutingContext routingContext,
8385
ChannelPromise channelInitializedPromise,
8486
NotificationConfig notificationConfig) {
87+
var exception = verifyNotificationConfigSupported(notificationConfig);
88+
if (exception != null) {
89+
channelInitializedPromise.setFailure(exception);
90+
return;
91+
}
8592
Channel channel = channelInitializedPromise.channel();
8693
HelloMessage message;
8794

@@ -91,14 +98,14 @@ public void initializeChannel(
9198
((InternalAuthToken) authToken).toMap(),
9299
routingContext.toMap(),
93100
includeDateTimeUtcPatchInHello(),
94-
includeNotificationSettings() ? notificationConfig : null);
101+
notificationConfig);
95102
} else {
96103
message = new HelloMessage(
97104
userAgent,
98105
((InternalAuthToken) authToken).toMap(),
99106
null,
100107
includeDateTimeUtcPatchInHello(),
101-
includeNotificationSettings() ? notificationConfig : null);
108+
notificationConfig);
102109
}
103110

104111
HelloResponseHandler handler = new HelloResponseHandler(channelInitializedPromise);
@@ -125,6 +132,10 @@ public CompletionStage<Void> beginTransaction(
125132
TransactionConfig config,
126133
String txType,
127134
NotificationConfig notificationConfig) {
135+
var exception = verifyNotificationConfigSupported(notificationConfig);
136+
if (exception != null) {
137+
return CompletableFuture.failedStage(exception);
138+
}
128139
try {
129140
verifyDatabaseNameBeforeTransaction(connection.databaseName());
130141
} catch (Exception error) {
@@ -139,7 +150,7 @@ public CompletionStage<Void> beginTransaction(
139150
connection.mode(),
140151
connection.impersonatedUser(),
141152
txType,
142-
includeNotificationSettings() ? notificationConfig : null);
153+
notificationConfig);
143154
connection.writeAndFlush(beginMessage, new BeginTxResponseHandler(beginTxFuture));
144155
return beginTxFuture;
145156
}
@@ -167,6 +178,10 @@ public ResultCursorFactory runInAutoCommitTransaction(
167178
TransactionConfig config,
168179
long fetchSize,
169180
NotificationConfig notificationConfig) {
181+
var exception = verifyNotificationConfigSupported(notificationConfig);
182+
if (exception != null) {
183+
throw exception;
184+
}
170185
verifyDatabaseNameBeforeTransaction(connection.databaseName());
171186
RunWithMetadataMessage runMessage = autoCommitTxRunMessage(
172187
query,
@@ -175,7 +190,7 @@ public ResultCursorFactory runInAutoCommitTransaction(
175190
connection.mode(),
176191
bookmarks,
177192
connection.impersonatedUser(),
178-
includeNotificationSettings() ? notificationConfig : null);
193+
notificationConfig);
179194
return buildResultCursorFactory(connection, query, bookmarkConsumer, null, runMessage, fetchSize);
180195
}
181196

@@ -214,7 +229,13 @@ protected boolean includeDateTimeUtcPatchInHello() {
214229
return false;
215230
}
216231

217-
protected boolean includeNotificationSettings() {
218-
return false;
232+
protected Neo4jException verifyNotificationConfigSupported(NotificationConfig notificationConfig) {
233+
Neo4jException exception = null;
234+
if (notificationConfig != null && !notificationConfig.equals(NotificationConfig.defaultConfig())) {
235+
exception = new UnsupportedFeatureException(String.format(
236+
"Notification configuration is not supported on Bolt %s",
237+
version().toString()));
238+
}
239+
return exception;
219240
}
220241
}

driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public void initializeChannel(
4646
RoutingContext routingContext,
4747
ChannelPromise channelInitializedPromise,
4848
NotificationConfig notificationConfig) {
49+
var exception = verifyNotificationConfigSupported(notificationConfig);
50+
if (exception != null) {
51+
channelInitializedPromise.setFailure(exception);
52+
return;
53+
}
4954
var channel = channelInitializedPromise.channel();
5055
HelloMessage message;
5156

driver/src/main/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Collections;
2525
import org.neo4j.driver.AuthToken;
2626
import org.neo4j.driver.NotificationConfig;
27+
import org.neo4j.driver.exceptions.Neo4jException;
2728
import org.neo4j.driver.internal.cluster.RoutingContext;
2829
import org.neo4j.driver.internal.handlers.HelloResponseHandler;
2930
import org.neo4j.driver.internal.handlers.LogonResponseHandler;
@@ -62,8 +63,8 @@ public void initializeChannel(
6263
}
6364

6465
@Override
65-
protected boolean includeNotificationSettings() {
66-
return true;
66+
protected Neo4jException verifyNotificationConfigSupported(NotificationConfig notificationConfig) {
67+
return null;
6768
}
6869

6970
@Override

0 commit comments

Comments
 (0)