Skip to content

Commit a3912a5

Browse files
authored
Introduce notification configuration, severity and category (#1396)
* Introduce notification configuration, severity and category Improve and expand the existing notification API. A new `NotificationSeverity` type represents a notification severity level. It includes 2 public constants: - `INFORMATION` - `WARNING` A new `NotificationCategory` type represents a notification category. It includes 6 public constants: - `HINT` - `UNRECOGNIZED` - `UNSUPPORTED` - `PERFORMANCE` - `DEPRECATION` - `GENERIC` The `Notification` class has been extended with the following 4 methods: - `Optional<NotificationSeverity> severityLevel()` - `Optional<String> rawSeverityLevel()` - `Optional<NotificationCategory> category()` - `Optional<String> rawCategory()` The `raw` methods return a `String` representation returned by the server. In case of an unrecognised value, both `severityLevel()` and `category()` methods return an empty `Optional`. This may happen if a new value is introduced in a future server version and a previous driver version does not support it. Additionally, an empty `Optional` may be returned when driver communicates with a server version that does not supply these values. The `severity()` method has been deprecated in favour of the `rawSeverityLevel()` method. A new `NotificationConfig` type has been introduced to allow notification preferences management. By default, the server determines what notifications are provided to the driver. However, user can set a minimum severity level and/or a set of disabled notification categories to manage its expectations. This feature is only supported on Bolt protocol version 5.2 and above. Both the `Config` and the `SessionConfig` support this new configuration. Sample usage: ```java // sets minimum notification severity level to WARNING // and explicitly disables both GENERIC and HINT notification categories var driverConfig = Config.builder() .withNotificationConfig(NotificationConfig.defaultConfig().enableMinimumSeverity(NotificationSeverity.WARNING).disableCategories(Set.of(NotificationCategory.GENERIC, NotificationCategory.HINT))) .build(); // disables all notifications var sessionConfig = SessionConfig.builder() .withNotificationConfig(NotificationConfig.disableAll()) .build(); ``` This update includes support for both 5.1 and 5.2 versions. The latter is required for the full support of the new notification updates. * Throw exception when notification configuration is not supported This update introduces a new `UnsupportedFeatureException`. An instance of this exception will be emitted if a custom `NotificationConfig` is used and the driver comes across a Bolt connection that does not support the notification configuration.
1 parent e2962b8 commit a3912a5

File tree

81 files changed

+2423
-266
lines changed

Some content is hidden

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

81 files changed

+2423
-266
lines changed

driver/clirr-ignored-differences.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,4 +433,28 @@
433433
<method>org.neo4j.driver.BookmarkManager queryTaskBookmarkManager()</method>
434434
</difference>
435435

436+
<difference>
437+
<className>org/neo4j/driver/summary/Notification</className>
438+
<differenceType>7012</differenceType>
439+
<method>java.util.Optional severityLevel()</method>
440+
</difference>
441+
442+
<difference>
443+
<className>org/neo4j/driver/summary/Notification</className>
444+
<differenceType>7012</differenceType>
445+
<method>java.util.Optional rawSeverityLevel()</method>
446+
</difference>
447+
448+
<difference>
449+
<className>org/neo4j/driver/summary/Notification</className>
450+
<differenceType>7012</differenceType>
451+
<method>java.util.Optional category()</method>
452+
</difference>
453+
454+
<difference>
455+
<className>org/neo4j/driver/summary/Notification</className>
456+
<differenceType>7012</differenceType>
457+
<method>java.util.Optional rawCategory()</method>
458+
</difference>
459+
436460
</differences>

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

Lines changed: 32 additions & 0 deletions
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;
@@ -143,6 +144,10 @@ public final class Config implements Serializable {
143144
* The user_agent configured for this driver.
144145
*/
145146
private final String userAgent;
147+
/**
148+
* The notification config.
149+
*/
150+
private final NotificationConfig notificationConfig;
146151
/**
147152
* The {@link MetricsAdapter}.
148153
*/
@@ -166,6 +171,7 @@ private Config(ConfigBuilder builder) {
166171
this.maxTransactionRetryTimeMillis = builder.maxTransactionRetryTimeMillis;
167172
this.resolver = builder.resolver;
168173
this.fetchSize = builder.fetchSize;
174+
this.notificationConfig = builder.notificationConfig;
169175

170176
this.eventLoopThreads = builder.eventLoopThreads;
171177
this.metricsAdapter = builder.metricsAdapter;
@@ -311,6 +317,15 @@ public long fetchSize() {
311317
return fetchSize;
312318
}
313319

320+
/**
321+
* Returns notification config.
322+
* @return the notification config
323+
* @since 5.7
324+
*/
325+
public NotificationConfig notificationConfig() {
326+
return notificationConfig;
327+
}
328+
314329
/**
315330
* Returns the number of {@link io.netty.channel.EventLoop} threads.
316331
* @return the number of threads
@@ -363,6 +378,7 @@ public static final class ConfigBuilder {
363378
private MetricsAdapter metricsAdapter = MetricsAdapter.DEV_NULL;
364379
private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE;
365380
private int eventLoopThreads = 0;
381+
private NotificationConfig notificationConfig = NotificationConfig.defaultConfig();
366382

367383
private ConfigBuilder() {}
368384

@@ -757,6 +773,22 @@ public ConfigBuilder withUserAgent(String userAgent) {
757773
return this;
758774
}
759775

776+
/**
777+
* Sets notification config.
778+
* <p>
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 the driver comes across a
781+
* Bolt connection that does not support this feature. For instance, when running a query.
782+
*
783+
* @param notificationConfig the notification config
784+
* @return this builder
785+
* @since 5.7
786+
*/
787+
public ConfigBuilder withNotificationConfig(NotificationConfig notificationConfig) {
788+
this.notificationConfig = Objects.requireNonNull(notificationConfig, "notificationConfig must not be null");
789+
return this;
790+
}
791+
760792
/**
761793
* Extracts the driver version from the driver jar MANIFEST.MF file.
762794
*/
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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;
20+
21+
import java.io.Serializable;
22+
import org.neo4j.driver.internal.InternalNotificationCategory;
23+
import org.neo4j.driver.internal.InternalNotificationCategory.Type;
24+
25+
/**
26+
* Notification category.
27+
*
28+
* @since 5.7
29+
*/
30+
public sealed interface NotificationCategory extends Serializable permits InternalNotificationCategory {
31+
/**
32+
* A hint category.
33+
* <p>
34+
* For instance, the given hint cannot be satisfied.
35+
*/
36+
NotificationCategory HINT = new InternalNotificationCategory(Type.HINT);
37+
38+
/**
39+
* An unrecognized category.
40+
* <p>
41+
* For instance, the query or command mentions entities that are unknown to the system.
42+
*/
43+
NotificationCategory UNRECOGNIZED = new InternalNotificationCategory(Type.UNRECOGNIZED);
44+
45+
/**
46+
* An unsupported category.
47+
* <p>
48+
* For instance, the query/command is trying to use features that are not supported by the current system or using
49+
* features that are experimental and should not be used in production.
50+
*/
51+
NotificationCategory UNSUPPORTED = new InternalNotificationCategory(Type.UNSUPPORTED);
52+
53+
/**
54+
* A performance category.
55+
* <p>
56+
* For instance, the query uses costly operations and might be slow.
57+
*/
58+
NotificationCategory PERFORMANCE = new InternalNotificationCategory(Type.PERFORMANCE);
59+
60+
/**
61+
* A deprecation category.
62+
* <p>
63+
* For instance, the query/command use deprecated features that should be replaced.
64+
*/
65+
NotificationCategory DEPRECATION = new InternalNotificationCategory(Type.DEPRECATION);
66+
67+
/**
68+
* A generic category.
69+
* <p>
70+
* For instance, notifications that are not part of a more specific class.
71+
*/
72+
NotificationCategory GENERIC = new InternalNotificationCategory(Type.GENERIC);
73+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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;
20+
21+
import java.io.Serializable;
22+
import java.util.Set;
23+
import org.neo4j.driver.internal.InternalNotificationConfig;
24+
import org.neo4j.driver.internal.InternalNotificationSeverity;
25+
import org.neo4j.driver.summary.ResultSummary;
26+
27+
/**
28+
* A notification configuration defining what notifications should be supplied by the server.
29+
* <p>
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.
37+
*
38+
* @since 5.7
39+
* @see ResultSummary#notifications()
40+
* @see org.neo4j.driver.summary.Notification
41+
*/
42+
public sealed interface NotificationConfig extends Serializable permits InternalNotificationConfig {
43+
/**
44+
* Returns a default notification configuration.
45+
* <p>
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.
50+
*
51+
* @return the default config
52+
*/
53+
static NotificationConfig defaultConfig() {
54+
return new InternalNotificationConfig(null, null);
55+
}
56+
57+
/**
58+
* A config that disables all notifications.
59+
*
60+
* @return the config that disables all notifications
61+
*/
62+
static NotificationConfig disableAllConfig() {
63+
return new InternalNotificationConfig(InternalNotificationSeverity.OFF, null);
64+
}
65+
66+
/**
67+
* Returns a config that sets a minimum severity level for notifications.
68+
*
69+
* @param minimumSeverity the minimum severity level
70+
* @return the config
71+
*/
72+
NotificationConfig enableMinimumSeverity(NotificationSeverity minimumSeverity);
73+
74+
/**
75+
* Returns a config that disables a set of notification categories.
76+
*
77+
* @param disabledCategories the categories to disable, an empty set means no categories are disabled
78+
* @return the config
79+
*/
80+
NotificationConfig disableCategories(Set<NotificationCategory> disabledCategories);
81+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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;
20+
21+
import static org.neo4j.driver.internal.InternalNotificationSeverity.Type;
22+
23+
import java.io.Serializable;
24+
import org.neo4j.driver.internal.InternalNotificationSeverity;
25+
26+
/**
27+
* Notification severity level.
28+
*
29+
* @since 5.7
30+
*/
31+
public sealed interface NotificationSeverity extends Serializable, Comparable<NotificationSeverity>
32+
permits InternalNotificationSeverity {
33+
/**
34+
* An information severity level.
35+
*/
36+
NotificationSeverity INFORMATION = new InternalNotificationSeverity(Type.INFORMATION, 800);
37+
/**
38+
* A warning severity level.
39+
*/
40+
NotificationSeverity WARNING = new InternalNotificationSeverity(Type.WARNING, 900);
41+
}

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

Lines changed: 34 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;
@@ -65,6 +66,10 @@ public final class SessionConfig implements Serializable {
6566
* The bookmark manager.
6667
*/
6768
private final BookmarkManager bookmarkManager;
69+
/**
70+
* The notification config.
71+
*/
72+
private final NotificationConfig notificationConfig;
6873

6974
private SessionConfig(Builder builder) {
7075
this.bookmarks = builder.bookmarks;
@@ -73,6 +78,7 @@ private SessionConfig(Builder builder) {
7378
this.fetchSize = builder.fetchSize;
7479
this.impersonatedUser = builder.impersonatedUser;
7580
this.bookmarkManager = builder.bookmarkManager;
81+
this.notificationConfig = builder.notificationConfig;
7682
}
7783

7884
/**
@@ -161,6 +167,15 @@ public Optional<BookmarkManager> bookmarkManager() {
161167
return Optional.ofNullable(bookmarkManager);
162168
}
163169

170+
/**
171+
* Returns notification config.
172+
* @return the notification config
173+
* @since 5.7
174+
*/
175+
public NotificationConfig notificationConfig() {
176+
return notificationConfig;
177+
}
178+
164179
@Override
165180
public boolean equals(Object o) {
166181
if (this == o) {
@@ -175,7 +190,8 @@ public boolean equals(Object o) {
175190
&& Objects.equals(database, that.database)
176191
&& Objects.equals(fetchSize, that.fetchSize)
177192
&& Objects.equals(impersonatedUser, that.impersonatedUser)
178-
&& Objects.equals(bookmarkManager, that.bookmarkManager);
193+
&& Objects.equals(bookmarkManager, that.bookmarkManager)
194+
&& Objects.equals(notificationConfig, that.notificationConfig);
179195
}
180196

181197
@Override
@@ -203,6 +219,7 @@ public static final class Builder {
203219
private String database = null;
204220
private String impersonatedUser = null;
205221
private BookmarkManager bookmarkManager;
222+
private NotificationConfig notificationConfig = NotificationConfig.defaultConfig();
206223

207224
private Builder() {}
208225

@@ -366,6 +383,22 @@ public Builder withBookmarkManager(BookmarkManager bookmarkManager) {
366383
return this;
367384
}
368385

386+
/**
387+
* Sets notification config.
388+
* <p>
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 the driver comes across a
391+
* Bolt connection that does not support this feature. For instance, when running a query.
392+
*
393+
* @param notificationConfig the notification config
394+
* @return this builder
395+
* @since 5.7
396+
*/
397+
public Builder withNotificationConfig(NotificationConfig notificationConfig) {
398+
this.notificationConfig = Objects.requireNonNull(notificationConfig, "notificationConfig must not be null");
399+
return this;
400+
}
401+
369402
/**
370403
* Builds the {@link SessionConfig}.
371404
* @return the config

0 commit comments

Comments
 (0)