> stageSupplier) {
- lock.lock();
+ lock(lock);
CompletableFuture.completedFuture(lock)
.thenCompose(ignored -> stageSupplier.get())
- .whenComplete((ignored, throwable) -> lock.unlock());
+ .whenComplete((ignored, throwable) -> unlock(lock));
+ }
+
+ /**
+ * Invokes {@link Lock#lock()} on the supplied {@link Lock}.
+ *
+ * This method is marked as allowed in the {@link org.neo4j.driver.internal.blockhound.Neo4jDriverBlockHoundIntegration}.
+ * @param lock the lock
+ * @since 5.11
+ */
+ private static void lock(Lock lock) {
+ lock.lock();
+ }
+
+ /**
+ * Invokes {@link Lock#unlock()} on the supplied {@link Lock}.
+ *
+ * This method is marked as allowed in the {@link org.neo4j.driver.internal.blockhound.Neo4jDriverBlockHoundIntegration}.
+ * @param lock the lock
+ * @since 5.11
+ */
+ private static void unlock(Lock lock) {
+ lock.unlock();
}
}
diff --git a/driver/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration b/driver/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
new file mode 100644
index 0000000000..1c9a3247b3
--- /dev/null
+++ b/driver/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
@@ -0,0 +1,18 @@
+# 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.
+
+org.neo4j.driver.internal.blockhound.Neo4jDriverBlockHoundIntegration
diff --git a/driver/src/test/java/org/neo4j/driver/internal/blockhound/LockUtilBlockHoundTest.java b/driver/src/test/java/org/neo4j/driver/internal/blockhound/LockUtilBlockHoundTest.java
new file mode 100644
index 0000000000..2aaf2c3974
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/blockhound/LockUtilBlockHoundTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.blockhound;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.locks.ReentrantLock;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.neo4j.driver.internal.util.LockUtil;
+import org.neo4j.driver.testutil.BlockHoundTest;
+import reactor.blockhound.BlockHound;
+import reactor.blockhound.BlockingOperationError;
+import reactor.core.scheduler.Schedulers;
+
+@BlockHoundTest
+class LockUtilBlockHoundTest {
+ @BeforeAll
+ static void setUp() {
+ BlockHound.install();
+ }
+
+ @Test
+ @SuppressWarnings("StatementWithEmptyBody")
+ void shouldAllowBlockingOnLock() {
+ var lock = new ReentrantLock();
+ var lockUnlockFuture = new CompletableFuture();
+ CompletableFuture.runAsync(() -> {
+ lock.lock();
+ lockUnlockFuture.join();
+ lock.unlock();
+ });
+ var testFuture = new CompletableFuture();
+ Schedulers.parallel().schedule(() -> {
+ try {
+ LockUtil.executeWithLock(lock, () -> {});
+ } catch (Throwable t) {
+ testFuture.completeExceptionally(t);
+ }
+ testFuture.complete(null);
+ });
+
+ while (lock.getQueueLength() != 1) {}
+ lockUnlockFuture.complete(null);
+ testFuture.join();
+ }
+
+ @Test
+ void shouldFailInternalBlockingCalls() {
+ var lock = new ReentrantLock();
+ var testFuture = new CompletableFuture();
+ Schedulers.parallel()
+ .schedule(() -> LockUtil.executeWithLock(lock, () -> {
+ try {
+ Thread.sleep(1);
+ } catch (Throwable e) {
+ testFuture.completeExceptionally(e);
+ return;
+ }
+ testFuture.complete(null);
+ }));
+
+ var exception =
+ assertThrows(CompletionException.class, testFuture::join).getCause();
+ assertEquals(BlockingOperationError.class, exception.getClass());
+ assertTrue(exception.getMessage().contains("java.lang.Thread.sleep"));
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/blockhound/Neo4jDriverBlockHoundIntegrationTest.java b/driver/src/test/java/org/neo4j/driver/internal/blockhound/Neo4jDriverBlockHoundIntegrationTest.java
new file mode 100644
index 0000000000..28bbd60f0b
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/blockhound/Neo4jDriverBlockHoundIntegrationTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.blockhound;
+
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+import reactor.blockhound.BlockHound;
+
+class Neo4jDriverBlockHoundIntegrationTest {
+ @Test
+ void shouldUseExistingMethodsInAllowBlockingCallsInside() {
+ var builder = mock(BlockHound.Builder.class);
+ given(builder.allowBlockingCallsInside(any(), any())).willAnswer(invocationOnMock -> {
+ var clsName = (String) invocationOnMock.getArgument(0);
+ var methodName = (String) invocationOnMock.getArgument(1);
+ var cls = Class.forName(clsName);
+ Arrays.stream(cls.getDeclaredMethods())
+ .map(Method::getName)
+ .filter(name -> name.equals(methodName))
+ .findAny()
+ .ifPresentOrElse(
+ ignored -> {},
+ () -> fail(String.format("%s.%s method has not been found", clsName, methodName)));
+ return builder;
+ });
+ var integration = new Neo4jDriverBlockHoundIntegration();
+
+ integration.applyTo(builder);
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/testutil/BlockHoundTest.java b/driver/src/test/java/org/neo4j/driver/testutil/BlockHoundTest.java
new file mode 100644
index 0000000000..e3322a5852
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/testutil/BlockHoundTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.testutil;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.jupiter.api.Tag;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Tag("blockHoundTest")
+public @interface BlockHoundTest {}
diff --git a/pom.xml b/pom.xml
index 0f697f4c87..bc1232d16e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,7 @@
1.18.28
23.0.0
1.11.1
+ 1.0.8.RELEASE
1.18.3
5.9.0
@@ -125,6 +126,12 @@
${micrometer.version}
provided