You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2022/02/25 09:53:59 UTC

[maven-resolver] 01/01: [MRESOLVER-245] Isolate and update tests

This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch MRESOLVER-245-isolate-tests
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git

commit 4bc7b1eb95e9076cd1ba6a4515654a379a8dcd9a
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Feb 25 10:52:37 2022 +0100

    [MRESOLVER-245] Isolate and update tests
    
    Main intent is to properly isolate ITs, but did other cleanup as well
    like patch update of Hazelcast and documentation updated as well.
---
 maven-resolver-named-locks-hazelcast/pom.xml       |  13 +-
 .../DirectHazelcastSemaphoreProvider.java}         |  30 +-
 .../HazelcastCPSemaphoreNamedLockFactory.java      |  41 +-
 ...HazelcastClientCPSemaphoreNamedLockFactory.java |  42 +-
 .../HazelcastSemaphoreNamedLockFactory.java        |  66 ++--
 .../hazelcast/HazelcastSemaphoreProvider.java}     |  39 +-
 .../src/site/markdown/index.md.vm                  |  54 ++-
 .../src/site/site.xml                              |   2 +-
 .../hazelcast/HazelcastCPSemaphoreAdapterIT.java   |  10 +-
 .../HazelcastCPSemaphoreNamedLockFactoryIT.java    |  17 +-
 .../HazelcastClientCPSemaphoreAdapterIT.java       |  23 +-
 ...zelcastClientCPSemaphoreNamedLockFactoryIT.java |  26 +-
 .../named/hazelcast/HazelcastClientUtils.java      |  94 ++---
 .../NamedLockFactoryAdapterTestSupport.java        | 421 +++++++++++----------
 .../hazelcast/NamedLockFactoryTestSupport.java     | 164 +++++---
 .../src/test/resources/hazelcast-client.xml        |   2 +-
 .../src/test/resources/hazelcast.xml               |  14 +-
 17 files changed, 578 insertions(+), 480 deletions(-)

diff --git a/maven-resolver-named-locks-hazelcast/pom.xml b/maven-resolver-named-locks-hazelcast/pom.xml
index d1597e0..e207dd0 100644
--- a/maven-resolver-named-locks-hazelcast/pom.xml
+++ b/maven-resolver-named-locks-hazelcast/pom.xml
@@ -52,7 +52,7 @@
     <dependency>
       <groupId>com.hazelcast</groupId>
       <artifactId>hazelcast</artifactId>
-      <version>5.0.1</version>
+      <version>5.0.2</version>
     </dependency>
     <dependency>
       <groupId>javax.inject</groupId>
@@ -121,6 +121,17 @@
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <argLine combine.self="append">
+                --add-modules java.se
+                --add-exports java.base/jdk.internal.ref=ALL-UNNAMED
+                --add-opens java.base/java.lang=ALL-UNNAMED
+                --add-opens java.base/java.nio=ALL-UNNAMED
+                --add-opens java.base/sun.nio.ch=ALL-UNNAMED
+                --add-opens java.management/sun.management=ALL-UNNAMED
+                --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
+              </argLine>
+            </configuration>
           </plugin>
         </plugins>
       </build>
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/DirectHazelcastSemaphoreProvider.java
similarity index 53%
copy from maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java
copy to maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/DirectHazelcastSemaphoreProvider.java
index c53f501..6901daf 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/DirectHazelcastSemaphoreProvider.java
@@ -19,21 +19,25 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.cp.ISemaphore;
 
-public class HazelcastCPSemaphoreNamedLockFactoryIT
-    extends NamedLockFactoryTestSupport {
-
-    @BeforeClass
-    public static void createNamedLockFactory() {
-        namedLockFactory = new HazelcastCPSemaphoreNamedLockFactory();
+/**
+ * Direct provider of {@link ISemaphore} instances: it simply uses the passed in lock name to create semaphore name out
+ * of it. This implies, that as many lock names are requested from it, this class will create as many semaphores in
+ * Hazelcast.
+ */
+public class DirectHazelcastSemaphoreProvider extends HazelcastSemaphoreProvider
+{
+    @Override
+    public ISemaphore acquireSemaphore( HazelcastInstance hazelcastInstance, String name )
+    {
+        return hazelcastInstance.getCPSubsystem().getSemaphore( NAME_PREFIX + name );
     }
 
-    @AfterClass
-    public static void cleanup() {
-        if (namedLockFactory != null) {
-            namedLockFactory.shutdown();
-        }
+    @Override
+    public void releaseSemaphore( HazelcastInstance hazelcastInstance, String name, ISemaphore semaphore )
+    {
+        // nothing
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactory.java b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactory.java
index 81e428e..3f110ea 100644
--- a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactory.java
+++ b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactory.java
@@ -19,32 +19,37 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import com.hazelcast.core.Hazelcast;
-
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+
 /**
- * {@link HazelcastSemaphoreNamedLockFactory} using Hazelcast and {@link
- * com.hazelcast.core.HazelcastInstance#getCPSubsystem()} method to get CP semaphore. For this to work, the Hazelcast
- * cluster the client is connecting to must be CP enabled cluster.
+ * {@link HazelcastSemaphoreNamedLockFactory} using {@link DirectHazelcastSemaphoreProvider} full Hazelcast member.
  */
 @Singleton
 @Named( HazelcastCPSemaphoreNamedLockFactory.NAME )
-public class HazelcastCPSemaphoreNamedLockFactory
-    extends HazelcastSemaphoreNamedLockFactory
+public class HazelcastCPSemaphoreNamedLockFactory extends HazelcastSemaphoreNamedLockFactory
 {
-  public static final String NAME = "semaphore-hazelcast";
+    public static final String NAME = "semaphore-hazelcast";
+
+    /**
+     * The default constructor: creates own instance of Hazelcast using standard Hazelcast configuration discovery.
+     */
+    @Inject
+    public HazelcastCPSemaphoreNamedLockFactory()
+    {
+        this( Hazelcast.newHazelcastInstance(), true );
+    }
 
-  @Inject
-  public HazelcastCPSemaphoreNamedLockFactory()
-  {
-    super(
-        Hazelcast.newHazelcastInstance(),
-        ( hazelcastInstance, name ) -> hazelcastInstance.getCPSubsystem().getSemaphore( NAME_PREFIX + name ),
-        false,
-        true
-    );
-  }
+    /**
+     * Constructor for customization.
+     */
+    public HazelcastCPSemaphoreNamedLockFactory( HazelcastInstance hazelcastInstance,
+                                                 boolean manageHazelcast )
+    {
+        super( hazelcastInstance, manageHazelcast, new DirectHazelcastSemaphoreProvider() );
+    }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactory.java b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactory.java
index 097d120..138f7bb 100644
--- a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactory.java
+++ b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactory.java
@@ -19,32 +19,38 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import com.hazelcast.client.HazelcastClient;
-
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import com.hazelcast.client.HazelcastClient;
+import com.hazelcast.core.HazelcastInstance;
+
 /**
- * Provider of {@link HazelcastSemaphoreNamedLockFactory} using Hazelcast Client and {@link
- * com.hazelcast.core.HazelcastInstance#getCPSubsystem()} method to get CP semaphore. For this to work, the Hazelcast
- * cluster the client is connecting to must be CP enabled cluster.
+ * {@link HazelcastSemaphoreNamedLockFactory} using {@link DirectHazelcastSemaphoreProvider} and Hazelcast client. The
+ * client must be configured to connect to some existing cluster (w/ proper configuration applied).
  */
 @Singleton
 @Named( HazelcastClientCPSemaphoreNamedLockFactory.NAME )
-public class HazelcastClientCPSemaphoreNamedLockFactory
-    extends HazelcastSemaphoreNamedLockFactory
+public class HazelcastClientCPSemaphoreNamedLockFactory extends HazelcastSemaphoreNamedLockFactory
 {
-  public static final String NAME = "semaphore-hazelcast-client";
+    public static final String NAME = "semaphore-hazelcast-client";
+
+    /**
+     * The default constructor: creates own instance of Hazelcast using standard Hazelcast configuration discovery.
+     */
+    @Inject
+    public HazelcastClientCPSemaphoreNamedLockFactory()
+    {
+        this( HazelcastClient.newHazelcastClient(), true );
+    }
 
-  @Inject
-  public HazelcastClientCPSemaphoreNamedLockFactory()
-  {
-    super(
-        HazelcastClient.newHazelcastClient(),
-        ( hazelcastInstance, name ) -> hazelcastInstance.getCPSubsystem().getSemaphore( NAME_PREFIX + name ),
-        false,
-        true
-    );
-  }
+    /**
+     * Constructor for customization.
+     */
+    public HazelcastClientCPSemaphoreNamedLockFactory( HazelcastInstance hazelcastInstance,
+                                                       boolean manageHazelcast )
+    {
+        super( hazelcastInstance, manageHazelcast, new DirectHazelcastSemaphoreProvider() );
+    }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreNamedLockFactory.java b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreNamedLockFactory.java
index 01450db..18a30fa 100644
--- a/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreNamedLockFactory.java
+++ b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreNamedLockFactory.java
@@ -19,82 +19,66 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
 import com.hazelcast.core.HazelcastInstance;
 import com.hazelcast.cp.ISemaphore;
 import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock;
 import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock.AdaptedSemaphore;
 import org.eclipse.aether.named.support.NamedLockFactorySupport;
 
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.BiFunction;
+import static java.util.Objects.requireNonNull;
 
 /**
- * Factory of {@link AdaptedSemaphoreNamedLock} instances using adapted Hazelcast {@link ISemaphore}. This class may
- * use {@link HazelcastInstance} backed by Hazelcast Server or Hazelcast Client.
+ * Factory of {@link AdaptedSemaphoreNamedLock} instances, using adapted Hazelcast {@link ISemaphore}. It delegates
+ * most the work to {@link HazelcastSemaphoreProvider} and this class just adapts the returned semaphore to named lock
+ * and caches {@link ISemaphore} instances, as recommended by Hazelcast.
  */
 public class HazelcastSemaphoreNamedLockFactory
-    extends NamedLockFactorySupport
+        extends NamedLockFactorySupport
 {
-    protected static final String NAME_PREFIX = "maven:resolver:";
-
-    private final HazelcastInstance hazelcastInstance;
+    protected final HazelcastInstance hazelcastInstance;
 
-    private final BiFunction<HazelcastInstance, String, ISemaphore> semaphoreFunction;
+    protected final boolean manageHazelcast;
 
-    private final boolean destroySemaphore;
-
-    private final boolean manageHazelcast;
+    private final HazelcastSemaphoreProvider hazelcastSemaphoreProvider;
 
     private final ConcurrentMap<String, ISemaphore> semaphores;
 
     public HazelcastSemaphoreNamedLockFactory(
-        final HazelcastInstance hazelcastInstance,
-        final BiFunction<HazelcastInstance, String, ISemaphore> semaphoreFunction,
-        final boolean destroySemaphore,
-        final boolean manageHazelcast
+            final HazelcastInstance hazelcastInstance,
+            final boolean manageHazelcast,
+            final HazelcastSemaphoreProvider hazelcastSemaphoreProvider
     )
     {
-        this.hazelcastInstance = hazelcastInstance;
-        this.semaphoreFunction = semaphoreFunction;
-        this.destroySemaphore = destroySemaphore;
+        this.hazelcastInstance = requireNonNull( hazelcastInstance );
         this.manageHazelcast = manageHazelcast;
+        this.hazelcastSemaphoreProvider = requireNonNull( hazelcastSemaphoreProvider );
         this.semaphores = new ConcurrentHashMap<>();
     }
 
     @Override
     protected AdaptedSemaphoreNamedLock createLock( final String name )
     {
-        ISemaphore semaphore = semaphores.computeIfAbsent( name, k ->
-        {
-            ISemaphore result = semaphoreFunction.apply( hazelcastInstance, k );
-            result.init( Integer.MAX_VALUE );
-            return result;
-        } );
+        ISemaphore semaphore = semaphores.computeIfAbsent( name,
+                k -> hazelcastSemaphoreProvider.acquireSemaphore( hazelcastInstance, name ) );
         return new AdaptedSemaphoreNamedLock( name, this, new HazelcastSemaphore( semaphore ) );
     }
 
     @Override
-    public void shutdown()
+    protected void destroyLock( final String name )
     {
-        if ( manageHazelcast )
-        {
-            hazelcastInstance.shutdown();
-        }
+        hazelcastSemaphoreProvider.releaseSemaphore( hazelcastInstance, name, semaphores.remove( name ) );
     }
 
     @Override
-    protected void destroyLock( final String name )
+    public void shutdown()
     {
-        ISemaphore semaphore = semaphores.remove( name );
-        if ( destroySemaphore )
+        if ( manageHazelcast )
         {
-            if ( semaphore == null )
-            {
-                throw new IllegalStateException( "Semaphore expected but does not exist: " + name );
-            }
-            semaphore.destroy();
+            hazelcastInstance.shutdown();
         }
     }
 
@@ -109,7 +93,7 @@ public class HazelcastSemaphoreNamedLockFactory
 
         @Override
         public boolean tryAcquire( final int perms, final long time, final TimeUnit unit )
-            throws InterruptedException
+                throws InterruptedException
         {
             return semaphore.tryAcquire( perms, time, unit );
         }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreProvider.java
similarity index 51%
copy from maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java
copy to maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreProvider.java
index 2718bec..b34ea4b 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/main/java/org/eclipse/aether/named/hazelcast/HazelcastSemaphoreProvider.java
@@ -19,27 +19,26 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.cp.ISemaphore;
 
-public class HazelcastClientCPSemaphoreNamedLockFactoryIT
-    extends NamedLockFactoryTestSupport {
-
-    private static HazelcastClientUtils utils;
+/**
+ * Support class for providers of {@link ISemaphore} instances.
+ */
+public abstract class HazelcastSemaphoreProvider
+{
+    /**
+     * Name prefix recommended using for simpler configuration of Hazelcast.
+     */
+    protected static final String NAME_PREFIX = "mvn:resolver:";
 
-    @BeforeClass
-    public static void createNamedLockFactory() {
-        utils = new HazelcastClientUtils().createCpCluster();
-        namedLockFactory = new HazelcastClientCPSemaphoreNamedLockFactory();
-    }
+    /**
+     * Invoked when new instance of semaphore needed for given name. must not return {@code null}.
+     */
+    public abstract ISemaphore acquireSemaphore( HazelcastInstance hazelcastInstance, String name );
 
-    @AfterClass
-    public static void cleanup() {
-        if (namedLockFactory != null) {
-            namedLockFactory.shutdown();
-        }
-        if (utils != null) {
-            utils.cleanup();
-        }
-    }
+    /**
+     * Invoked when passed in semaphore associated with passed in name is not to be used anymore.
+     */
+    public abstract void releaseSemaphore( HazelcastInstance hazelcastInstance, String name, ISemaphore semaphore );
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/site/markdown/index.md.vm b/maven-resolver-named-locks-hazelcast/src/site/markdown/index.md.vm
index 40f629c..671e2d7 100644
--- a/maven-resolver-named-locks-hazelcast/src/site/markdown/index.md.vm
+++ b/maven-resolver-named-locks-hazelcast/src/site/markdown/index.md.vm
@@ -19,40 +19,60 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-This module implement named locks using Hazelcast. It provides two implementations, that are distributed and rely on
-Hazelcast 4.x ISemaphores.
+This module implement named locks using Hazelcast. It provides two implementations, using members or clients and
+rely on Hazelcast ISemaphore instances.
 
 Out of the box "hazelcast" (distributed) named lock implementations are the following:
 
-- `semaphore-hazelcast` implemented in `org.eclipse.aether.named.hazelcast.HazelcastCPSemaphoreNamedLockFactory` that uses
-  Hazelcast backed `com.hazelcast.cp.ISemaphore`. Full Hazelcast member is used here.
+- `semaphore-hazelcast` implemented in `org.eclipse.aether.named.hazelcast.HazelcastCPSemaphoreNamedLockFactory`.
+  Full Hazelcast member is used here.
 - `semaphore-hazelcast-client` implemented in `org.eclipse.aether.named.hazelcast.HazelcastClientCPSemaphoreNamedLockFactory`
-  that uses Hazelcast Client backed `com.hazelcast.cp.ISemaphore`. This implementation uses Hazelcast Client, so
-  connection to some existing Hazelcast cluster, and its existence is a requirement.
+  This implementation uses Hazelcast Client, so existing Hazelcast cluster to connect to is a requirement.
+
+The semaphore name prefix is `mvn:resolver:` and pre-configuring semaphores in Hazelcast is a must. The Hazelcast
+configuration must have the following entry:
+
+- Name prefix: `mvn:resolver:` (use pattern matching configuration)
+- JDK compatible: true
+- Permit count: `Integer.MAX_VALUE` (value `2147483647`)
+
+Example Hazelcast XML relevant snippet:
+
+```xml
+    <cp-subsystem>
+        <semaphores>
+            <semaphore>
+                <name>mvn:resolver:*</name>
+                <jdk-compatible>true</jdk-compatible>
+                <initial-permits>2147483647</initial-permits>
+            </semaphore>
+        </semaphores>
+    </cp-subsystem>
+```
+
+Without this configuration present, this library will not work.
 
 ${esc.hash}${esc.hash} Open Issues/Notes
 
-- Usage from plugins has not been tested yet.
 - The `furnace-maven-plugin` does not work this implementation because it uses `ServiceLocator` instead
   of dependency injection.
 
 ${esc.hash}${esc.hash} Open Issues/Notes for Maven Resolver integrators
 
-To use this implementation within your project, depending on how you integrate, you have following options:
-- If you use Sisu DI, then all you need is to provide this module (and its dependencies) on classpath and you are done.
-- If you use Guice, you need to add this module (and its dependencies) upfront, and bind them explicitly.
+To use this implementation within your project, depending on how you integrate, you have the following options:
+
+- If you use Sisu DI, then all you need is to provide this module (and Hazelcast JAR) on classpath, and you are done.
+- If you use Guice, you need to add this module (and its dependencies) upfront to classpath, and bind them explicitly.
 - If you use ServiceLocator, be aware it is deprecated, and you should move away from it. In this case, simplest is
   to roll your own "bootstrap" class that does pretty much same thing as ServiceLocator was, and extend it to
   instantiate these components as well.
 
 ${esc.hash}${esc.hash} Installation/Testing
 
-- Create the directory `${maven.home}/lib/ext/hazelcast/`.
-- Modify `${maven.home}/bin/m2.conf` by adding `load ${maven.home}/lib/ext/hazelcast/*.jar`
-  right after the `${maven.conf}/logging` line.
-- Copy the following dependency from Maven Central to `${maven.home}/lib/ext/hazelcast/`:
+- Copy the following JARs from Maven Central to `${maven.home}/lib/ext/`:
       <pre class="source">
-      └── <a href="https://repo.maven.apache.org/maven2/com/hazelcast/hazelcast/4.1.1/hazelcast-4.1.1.jar">hazelcast-4.1.1.jar</a></pre>
-- Optionally configure Hazelcast instance with `${maven.conf}/hazelcast.xml` or `${maven.conf}/hazelcast-client.xml`
-  (see Hazelcast documentation for possibilities, or, see test resources of this project as starter).
+      ├── <a href="https://repo.maven.apache.org/maven2/org/apache/maven/resolver/${project.artifactId}/${project.version}/${project.artifactId}-${project.version}.jar">${project.artifactId}-${project.version}.jar</a>
+      └── <a href="https://repo.maven.apache.org/maven2/com/hazelcast/hazelcast/5.0.2/hazelcast-5.0.2.jar">hazelcast-5.0.2.jar</a></pre>
+- Configure Hazelcast instance with `${maven.conf}/hazelcast.xml` or `${maven.conf}/hazelcast-client.xml` (if client used).
+  See Hazelcast documentation, default Hazelcast configuration discovery is being used.
 - Now start a multithreaded Maven build on your project and make sure `NamedSyncContextFactory` is being used.
diff --git a/maven-resolver-named-locks-hazelcast/src/site/site.xml b/maven-resolver-named-locks-hazelcast/src/site/site.xml
index 0a3c423..38d8d76 100644
--- a/maven-resolver-named-locks-hazelcast/src/site/site.xml
+++ b/maven-resolver-named-locks-hazelcast/src/site/site.xml
@@ -21,7 +21,7 @@ under the License.
 
 <project xmlns="http://maven.apache.org/DECORATION/1.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 https://maven.apache.org/xsd/decoration-1.0.0.xsd"
   name="Named Locks using Hazelcast">
   <body>
     <menu name="Overview">
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreAdapterIT.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreAdapterIT.java
index d2faad8..8f69655 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreAdapterIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreAdapterIT.java
@@ -22,10 +22,14 @@ package org.eclipse.aether.named.hazelcast;
 import org.junit.BeforeClass;
 
 public class HazelcastCPSemaphoreAdapterIT
-    extends NamedLockFactoryAdapterTestSupport {
+        extends NamedLockFactoryAdapterTestSupport
+{
 
     @BeforeClass
-    public static void createNamedLockFactory() {
-        setNamedLockFactory(new HazelcastCPSemaphoreNamedLockFactory());
+    public static void createNamedLockFactory()
+    {
+        String clusterName = utils.clusterName( HazelcastCPSemaphoreAdapterIT.class );
+        setNamedLockFactory(
+                new HazelcastCPSemaphoreNamedLockFactory( utils.createMember( clusterName ), true ) );
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java
index c53f501..cd1a091 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastCPSemaphoreNamedLockFactoryIT.java
@@ -19,21 +19,16 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
 public class HazelcastCPSemaphoreNamedLockFactoryIT
-    extends NamedLockFactoryTestSupport {
+        extends NamedLockFactoryTestSupport
+{
 
     @BeforeClass
-    public static void createNamedLockFactory() {
-        namedLockFactory = new HazelcastCPSemaphoreNamedLockFactory();
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        if (namedLockFactory != null) {
-            namedLockFactory.shutdown();
-        }
+    public static void createNamedLockFactory()
+    {
+        String clusterName = utils.clusterName( HazelcastCPSemaphoreNamedLockFactoryIT.class );
+        namedLockFactory = new HazelcastCPSemaphoreNamedLockFactory( utils.createMember( clusterName ), true );
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreAdapterIT.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreAdapterIT.java
index b5d0256..c770b7a 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreAdapterIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreAdapterIT.java
@@ -19,24 +19,17 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
 public class HazelcastClientCPSemaphoreAdapterIT
-    extends NamedLockFactoryAdapterTestSupport {
-
-    private static HazelcastClientUtils utils;
-
+        extends NamedLockFactoryAdapterTestSupport
+{
     @BeforeClass
-    public static void createNamedLockFactory() {
-        utils = new HazelcastClientUtils().createCpCluster();
-        setNamedLockFactory(new HazelcastClientCPSemaphoreNamedLockFactory());
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        if (utils != null) {
-            utils.cleanup();
-        }
+    public static void createNamedLockFactory()
+    {
+        String clusterName = utils.clusterName( HazelcastClientCPSemaphoreAdapterIT.class );
+        utils.createMember( clusterName );
+        setNamedLockFactory(
+                new HazelcastClientCPSemaphoreNamedLockFactory( utils.createClient( clusterName ), true ) );
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java
index 2718bec..be50ed5 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientCPSemaphoreNamedLockFactoryIT.java
@@ -19,27 +19,17 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
-import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
 public class HazelcastClientCPSemaphoreNamedLockFactoryIT
-    extends NamedLockFactoryTestSupport {
-
-    private static HazelcastClientUtils utils;
-
+        extends NamedLockFactoryTestSupport
+{
     @BeforeClass
-    public static void createNamedLockFactory() {
-        utils = new HazelcastClientUtils().createCpCluster();
-        namedLockFactory = new HazelcastClientCPSemaphoreNamedLockFactory();
-    }
-
-    @AfterClass
-    public static void cleanup() {
-        if (namedLockFactory != null) {
-            namedLockFactory.shutdown();
-        }
-        if (utils != null) {
-            utils.cleanup();
-        }
+    public static void createNamedLockFactory()
+    {
+        String clusterName = utils.clusterName( HazelcastClientCPSemaphoreNamedLockFactoryIT.class );
+        utils.createMember( clusterName );
+        namedLockFactory =
+                new HazelcastClientCPSemaphoreNamedLockFactory( utils.createClient( clusterName ), true );
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientUtils.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientUtils.java
index 1d3ecc2..ec54706 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientUtils.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/HazelcastClientUtils.java
@@ -19,70 +19,74 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.IntStream;
+
+import com.hazelcast.client.HazelcastClient;
+import com.hazelcast.client.config.ClientConfig;
 import com.hazelcast.config.Config;
-import com.hazelcast.config.cp.CPSubsystemConfig;
 import com.hazelcast.core.Hazelcast;
 import com.hazelcast.core.HazelcastInstance;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
- * Hazelcast Client connects to remote server (or servers, in case of cluster). This class is a helper to
- * help create and validate remote Hazelcast environment, that Hazelcast Client will connect to.
+ * Hazelcast test utilities.
  */
-public final class HazelcastClientUtils {
-
-    private static final int CP_CLUSTER_NODES = 3;
-
-    private List<HazelcastInstance> servers;
+public final class HazelcastClientUtils
+{
+    private final List<HazelcastInstance> servers = new ArrayList<>();
 
     /**
-     * Creates a Hazelcast server instance, that client may connect to.
+     * Creates similar but still randomized name.
      */
-    public HazelcastClientUtils createSingleServer() {
-        servers = Collections.singletonList(Hazelcast.newHazelcastInstance());
-        return this;
+    public String clusterName( Class<?> klazz )
+    {
+        return String.format( "%s-%s", klazz.getSimpleName(), UUID.randomUUID() );
     }
 
     /**
-     * Creates a Hazelcast CP cluster, that client may connect to. When this method returns, cluster is not only
-     * created but it is properly formed as well.
+     * Creates single Hazelcast client instance.
      */
-    public HazelcastClientUtils createCpCluster() {
-        ArrayList<HazelcastInstance> instances = new ArrayList<>(CP_CLUSTER_NODES);
-        for (int i = 0; i < CP_CLUSTER_NODES; i++) {
-            HazelcastInstance instance = Hazelcast.newHazelcastInstance(
-                loadCPNodeConfig().setInstanceName("node" + i)
-            );
-            instances.add(instance);
-        }
-        servers = instances;
+    public synchronized HazelcastInstance createClient( String clusterName )
+    {
+        ClientConfig config = ClientConfig.load();
+        config.setClusterName( clusterName );
+        return HazelcastClient.newHazelcastClient( config );
+    }
 
-        // make sure HZ CP Cluster is ready
-        for (HazelcastInstance instance : servers) {
-            // this call will block until CP cluster if formed
-            // important thing here is that this blocking does not happen during timeout surrounded test
-            // hence, once this method returns, the CP cluster is "ready for use" without any delay.
-            instance.getCPSubsystem().getAtomicLong(instance.getName());
-        }
-        return this;
+    /**
+     * Creates single Hazelcast member instance.
+     */
+    public synchronized HazelcastInstance createMember( String clusterName )
+    {
+        return createMembers( 1, clusterName ).get( 0 );
     }
 
     /**
-     * Shuts down the created server(s)
+     * Creates given count of Hazelcast member instances.
      */
-    public void cleanup() {
-        if (servers != null) {
-            servers.forEach(HazelcastInstance::shutdown);
-        }
+    public synchronized List<HazelcastInstance> createMembers( int memberCount, String clusterName )
+    {
+        Config config = Config.load();
+        config.setClusterName( clusterName );
+        ArrayList<HazelcastInstance> result = new ArrayList<>( memberCount );
+        IntStream.range( 0, memberCount ).forEach( i -> {
+                    config.setInstanceName( "node-" + i );
+                    HazelcastInstance instance = Hazelcast.newHazelcastInstance( config );
+                    result.add( instance );
+                    servers.add( instance );
+                }
+        );
+        return result;
     }
 
-    private Config loadCPNodeConfig() {
-        // "cluster" for CP needs some config tweak from the test/resources/hazelcast.xml
-        Config config = Config.load().setCPSubsystemConfig(new CPSubsystemConfig().setCPMemberCount(3));
-        config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(true);
-        return config;
+    /**
+     * Shuts down the created instances.
+     */
+    public synchronized void cleanup()
+    {
+        servers.forEach( HazelcastInstance::shutdown );
+        servers.clear();
     }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java
index fc85955..db5beb2 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java
@@ -19,6 +19,14 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.SyncContext;
 import org.eclipse.aether.artifact.DefaultArtifact;
@@ -33,14 +41,6 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -49,203 +49,232 @@ import static org.mockito.Mockito.when;
  */
 public abstract class NamedLockFactoryAdapterTestSupport
 {
-  private static final long ADAPTER_TIME = 100L;
+    protected static final HazelcastClientUtils utils = new HazelcastClientUtils();
+
+    private static final long ADAPTER_TIME = 100L;
+
+    private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS;
+
+    /**
+     * Subclass should populate this field, using {@link #setNamedLockFactory(NamedLockFactory)}, but subclass
+     * must take care of proper cleanup as well, if needed!
+     */
+    private static NamedLockFactoryAdapter adapter;
+
+    private RepositorySystemSession session;
+
+    protected static void setNamedLockFactory( final NamedLockFactory namedLockFactory )
+    {
+        adapter = new NamedLockFactoryAdapter(
+                new DiscriminatingNameMapper( new GAVNameMapper() ), namedLockFactory
+        );
+    }
 
-  private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS;
+    @AfterClass
+    public static void cleanup()
+    {
+        if ( adapter != null )
+        {
+            adapter.shutdown();
+        }
 
-  /**
-   * Subclass should populate this field, using {@link #setNamedLockFactory(NamedLockFactory)}, but subclass
-   * must take care of proper cleanup as well, if needed!
-   */
-  private static NamedLockFactoryAdapter adapter;
+        utils.cleanup();
+    }
 
-  private RepositorySystemSession session;
+    @Before
+    public void before() throws IOException
+    {
+        Files.createDirectories( Paths.get( System.getProperty( "java.io.tmpdir" ) ) ); // hack for Surefire
+        LocalRepository localRepository = new LocalRepository( Files.createTempDirectory( "test" ).toFile() );
+        session = mock( RepositorySystemSession.class );
+        when( session.getLocalRepository() ).thenReturn( localRepository );
+        HashMap<String, Object> config = new HashMap<>();
+        config.put( NamedLockFactoryAdapter.TIME_KEY, String.valueOf( ADAPTER_TIME ) );
+        config.put( NamedLockFactoryAdapter.TIME_UNIT_KEY, ADAPTER_TIME_UNIT.name() );
+        when( session.getConfigProperties() ).thenReturn( config );
+    }
 
-  protected static void setNamedLockFactory(final NamedLockFactory namedLockFactory) {
-    adapter = new NamedLockFactoryAdapter(
-            new DiscriminatingNameMapper(new GAVNameMapper()), namedLockFactory
-    );
-  }
+    @Test
+    public void justCreateAndClose()
+    {
+        adapter.newInstance( session, false ).close();
+    }
 
-  @AfterClass
-  public static void cleanupAdapter() {
-    if (adapter != null) {
-      adapter.shutdown();
+    @Test
+    public void justAcquire()
+    {
+        try ( SyncContext syncContext = adapter.newInstance( session, false ) )
+        {
+            syncContext.acquire(
+                    Arrays.asList( new DefaultArtifact( "groupId:artifactId:1.0" ),
+                            new DefaultArtifact( "groupId:artifactId:1.1" ) ),
+                    null
+            );
+        }
     }
-  }
-
-  @Before
-  public void before() throws IOException {
-    Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire
-    LocalRepository localRepository = new LocalRepository(Files.createTempDirectory("test").toFile());
-    session = mock(RepositorySystemSession.class);
-    when(session.getLocalRepository()).thenReturn(localRepository);
-    HashMap<String, Object> config = new HashMap<>();
-    config.put(NamedLockFactoryAdapter.TIME_KEY, String.valueOf(ADAPTER_TIME));
-    config.put(NamedLockFactoryAdapter.TIME_UNIT_KEY, ADAPTER_TIME_UNIT.name());
-    when(session.getConfigProperties()).thenReturn(config);
-  }
-
-  @Test
-  public void justCreateAndClose() {
-    adapter.newInstance(session, false).close();
-  }
-
-  @Test
-  public void justAcquire() {
-    try (SyncContext syncContext = adapter.newInstance(session, false)) {
-      syncContext.acquire(
-          Arrays.asList(new DefaultArtifact("groupId:artifactId:1.0"), new DefaultArtifact("groupId:artifactId:1.1")),
-          null
-      );
+
+    @Test( timeout = 5000 )
+    public void sharedAccess() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 2 ); // we expect 2 winners
+        CountDownLatch losers = new CountDownLatch( 0 ); // we expect 0 losers
+        Thread t1 = new Thread( new Access( true, winners, losers, adapter, session, null ) );
+        Thread t2 = new Thread( new Access( true, winners, losers, adapter, session, null ) );
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+        winners.await();
+        losers.await();
     }
-  }
-
-  @Test(timeout = 5000)
-  public void sharedAccess() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
-    CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
-    Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
-    Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null));
-    t1.start();
-    t2.start();
-    t1.join();
-    t2.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void exclusiveAccess() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
-    CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
-    Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
-    Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
-    t1.start();
-    t2.start();
-    t1.join();
-    t2.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void mixedAccess() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
-    CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
-    Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
-    Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
-    t1.start();
-    t2.start();
-    t1.join();
-    t2.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void nestedSharedShared() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
-    CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
-    Thread t1 = new Thread(
-            new Access(true, winners, losers, adapter, session,
-                    new Access(true, winners, losers, adapter, session, null)
-            )
-    );
-    t1.start();
-    t1.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void nestedExclusiveShared() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
-    CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
-    Thread t1 = new Thread(
-            new Access(false, winners, losers, adapter, session,
-                    new Access(true, winners, losers, adapter, session, null)
-            )
-    );
-    t1.start();
-    t1.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void nestedExclusiveExclusive() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
-    CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
-    Thread t1 = new Thread(
-            new Access(false, winners, losers, adapter, session,
-                    new Access(false, winners, losers, adapter, session, null)
-            )
-    );
-    t1.start();
-    t1.join();
-    winners.await();
-    losers.await();
-  }
-
-  @Test(timeout = 5000)
-  public void nestedSharedExclusive() throws InterruptedException {
-    CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner (outer)
-    CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner)
-    Thread t1 = new Thread(
-            new Access(true, winners, losers, adapter, session,
-                    new Access(false, winners, losers, adapter, session, null)
-            )
-    );
-    t1.start();
-    t1.join();
-    winners.await();
-    losers.await();
-  }
-
-  private static class Access implements Runnable {
-    final boolean shared;
-    final CountDownLatch winner;
-    final CountDownLatch loser;
-    final NamedLockFactoryAdapter adapter;
-    final RepositorySystemSession session;
-    final Access chained;
-
-    public Access(boolean shared,
-                  CountDownLatch winner,
-                  CountDownLatch loser,
-                  NamedLockFactoryAdapter adapter,
-                  RepositorySystemSession session,
-                  Access chained) {
-      this.shared = shared;
-      this.winner = winner;
-      this.loser = loser;
-      this.adapter = adapter;
-      this.session = session;
-      this.chained = chained;
+
+    @Test( timeout = 5000 )
+    public void exclusiveAccess() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 1 ); // we expect 1 winner
+        CountDownLatch losers = new CountDownLatch( 1 ); // we expect 1 loser
+        Thread t1 = new Thread( new Access( false, winners, losers, adapter, session, null ) );
+        Thread t2 = new Thread( new Access( false, winners, losers, adapter, session, null ) );
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+        winners.await();
+        losers.await();
     }
 
-    @Override
-    public void run() {
-      try {
-        try (SyncContext syncContext = adapter.newInstance(session, shared)) {
-          syncContext.acquire(
-                  Arrays.asList(new DefaultArtifact("groupId:artifactId:1.0"), new DefaultArtifact("groupId:artifactId:1.1")),
-                  null
-          );
-          winner.countDown();
-          if (chained != null) {
-            chained.run();
-          }
-          loser.await();
-        } catch (IllegalStateException e) {
-          loser.countDown();
-          winner.await();
+    @Test( timeout = 5000 )
+    public void mixedAccess() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 1 ); // we expect 1 winner
+        CountDownLatch losers = new CountDownLatch( 1 ); // we expect 1 loser
+        Thread t1 = new Thread( new Access( true, winners, losers, adapter, session, null ) );
+        Thread t2 = new Thread( new Access( false, winners, losers, adapter, session, null ) );
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+        winners.await();
+        losers.await();
+    }
+
+    @Test( timeout = 5000 )
+    public void nestedSharedShared() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 2 ); // we expect 2 winners
+        CountDownLatch losers = new CountDownLatch( 0 ); // we expect 0 losers
+        Thread t1 = new Thread(
+                new Access( true, winners, losers, adapter, session,
+                        new Access( true, winners, losers, adapter, session, null )
+                )
+        );
+        t1.start();
+        t1.join();
+        winners.await();
+        losers.await();
+    }
+
+    @Test( timeout = 5000 )
+    public void nestedExclusiveShared() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 2 ); // we expect 2 winners
+        CountDownLatch losers = new CountDownLatch( 0 ); // we expect 0 losers
+        Thread t1 = new Thread(
+                new Access( false, winners, losers, adapter, session,
+                        new Access( true, winners, losers, adapter, session, null )
+                )
+        );
+        t1.start();
+        t1.join();
+        winners.await();
+        losers.await();
+    }
+
+    @Test( timeout = 5000 )
+    public void nestedExclusiveExclusive() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 2 ); // we expect 2 winners
+        CountDownLatch losers = new CountDownLatch( 0 ); // we expect 0 losers
+        Thread t1 = new Thread(
+                new Access( false, winners, losers, adapter, session,
+                        new Access( false, winners, losers, adapter, session, null )
+                )
+        );
+        t1.start();
+        t1.join();
+        winners.await();
+        losers.await();
+    }
+
+    @Test( timeout = 5000 )
+    public void nestedSharedExclusive() throws InterruptedException
+    {
+        CountDownLatch winners = new CountDownLatch( 1 ); // we expect 1 winner (outer)
+        CountDownLatch losers = new CountDownLatch( 1 ); // we expect 1 loser (inner)
+        Thread t1 = new Thread(
+                new Access( true, winners, losers, adapter, session,
+                        new Access( false, winners, losers, adapter, session, null )
+                )
+        );
+        t1.start();
+        t1.join();
+        winners.await();
+        losers.await();
+    }
+
+    private static class Access implements Runnable
+    {
+        final boolean shared;
+        final CountDownLatch winner;
+        final CountDownLatch loser;
+        final NamedLockFactoryAdapter adapter;
+        final RepositorySystemSession session;
+        final Access chained;
+
+        public Access( boolean shared,
+                       CountDownLatch winner,
+                       CountDownLatch loser,
+                       NamedLockFactoryAdapter adapter,
+                       RepositorySystemSession session,
+                       Access chained )
+        {
+            this.shared = shared;
+            this.winner = winner;
+            this.loser = loser;
+            this.adapter = adapter;
+            this.session = session;
+            this.chained = chained;
+        }
+
+        @Override
+        public void run()
+        {
+            try
+            {
+                try ( SyncContext syncContext = adapter.newInstance( session, shared ) )
+                {
+                    syncContext.acquire(
+                            Arrays.asList( new DefaultArtifact( "groupId:artifactId:1.0" ),
+                                    new DefaultArtifact( "groupId:artifactId:1.1" ) ),
+                            null
+                    );
+                    winner.countDown();
+                    if ( chained != null )
+                    {
+                        chained.run();
+                    }
+                    loser.await();
+                }
+                catch ( IllegalStateException e )
+                {
+                    loser.countDown();
+                    winner.await();
+                }
+            }
+            catch ( InterruptedException e )
+            {
+                Assert.fail( "interrupted" );
+            }
         }
-      }
-      catch (InterruptedException e) {
-        Assert.fail("interrupted");
-      }
     }
-  }
 }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryTestSupport.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryTestSupport.java
index c128e7f..04b009c 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryTestSupport.java
+++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryTestSupport.java
@@ -19,16 +19,17 @@ package org.eclipse.aether.named.hazelcast;
  * under the License.
  */
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import org.eclipse.aether.named.NamedLock;
 import org.eclipse.aether.named.NamedLockFactory;
+import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
@@ -37,86 +38,112 @@ import static org.hamcrest.Matchers.sameInstance;
 /**
  * UT support for {@link NamedLockFactory}.
  */
-public abstract class NamedLockFactoryTestSupport {
+public abstract class NamedLockFactoryTestSupport
+{
+    protected static final HazelcastClientUtils utils = new HazelcastClientUtils();
 
     protected static NamedLockFactory namedLockFactory;
 
     @Rule
     public TestName testName = new TestName();
 
+    @AfterClass
+    public static void cleanup()
+    {
+        if ( namedLockFactory != null )
+        {
+            namedLockFactory.shutdown();
+        }
+        utils.cleanup();
+    }
+
     @Test
-    public void refCounting() {
+    public void refCounting()
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name);
-             NamedLock two = namedLockFactory.getLock(name)) {
-            assertThat(one, sameInstance(two));
+        try ( NamedLock one = namedLockFactory.getLock( name );
+              NamedLock two = namedLockFactory.getLock( name ) )
+        {
+            assertThat( one, sameInstance( two ) );
             one.close();
             two.close();
 
-            try (NamedLock three = namedLockFactory.getLock(name)) {
-                assertThat(three, not(sameInstance(two)));
+            try ( NamedLock three = namedLockFactory.getLock( name ) )
+            {
+                assertThat( three, not( sameInstance( two ) ) );
             }
         }
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void unlockWoLock() {
+    @Test( expected = IllegalStateException.class )
+    public void unlockWoLock()
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name)) {
+        try ( NamedLock one = namedLockFactory.getLock( name ) )
+        {
             one.unlock();
         }
     }
 
     @Test
-    public void wwBoxing() throws InterruptedException {
+    public void wwBoxing() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name)) {
-            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
-            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
+        try ( NamedLock one = namedLockFactory.getLock( name ) )
+        {
+            assertThat( one.lockExclusively( 1L, TimeUnit.MILLISECONDS ), is( true ) );
+            assertThat( one.lockExclusively( 1L, TimeUnit.MILLISECONDS ), is( true ) );
             one.unlock();
             one.unlock();
         }
     }
 
     @Test
-    public void rrBoxing() throws InterruptedException {
+    public void rrBoxing() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name)) {
-            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
-            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
+        try ( NamedLock one = namedLockFactory.getLock( name ) )
+        {
+            assertThat( one.lockShared( 1L, TimeUnit.MILLISECONDS ), is( true ) );
+            assertThat( one.lockShared( 1L, TimeUnit.MILLISECONDS ), is( true ) );
             one.unlock();
             one.unlock();
         }
     }
 
     @Test
-    public void wrBoxing() throws InterruptedException {
+    public void wrBoxing() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name)) {
-            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
-            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
+        try ( NamedLock one = namedLockFactory.getLock( name ) )
+        {
+            assertThat( one.lockExclusively( 1L, TimeUnit.MILLISECONDS ), is( true ) );
+            assertThat( one.lockShared( 1L, TimeUnit.MILLISECONDS ), is( true ) );
             one.unlock();
             one.unlock();
         }
     }
 
     @Test
-    public void rwBoxing() throws InterruptedException {
+    public void rwBoxing() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        try (NamedLock one = namedLockFactory.getLock(name)) {
-            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
-            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(false));
+        try ( NamedLock one = namedLockFactory.getLock( name ) )
+        {
+            assertThat( one.lockShared( 1L, TimeUnit.MILLISECONDS ), is( true ) );
+            assertThat( one.lockExclusively( 1L, TimeUnit.MILLISECONDS ), is( false ) );
             one.unlock();
         }
     }
 
-    @Test(timeout = 5000)
-    public void sharedAccess() throws InterruptedException {
+    @Test( timeout = 5000 )
+    public void sharedAccess() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        CountDownLatch winners = new CountDownLatch(2); // we expect 2 winner
-        CountDownLatch losers = new CountDownLatch(0); // we expect 0 loser
-        Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
-        Thread t2 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
+        CountDownLatch winners = new CountDownLatch( 2 ); // we expect 2 winner
+        CountDownLatch losers = new CountDownLatch( 0 ); // we expect 0 loser
+        Thread t1 = new Thread( new Access( namedLockFactory, name, true, winners, losers ) );
+        Thread t2 = new Thread( new Access( namedLockFactory, name, true, winners, losers ) );
         t1.start();
         t2.start();
         t1.join();
@@ -125,13 +152,14 @@ public abstract class NamedLockFactoryTestSupport {
         losers.await();
     }
 
-    @Test(timeout = 5000)
-    public void exclusiveAccess() throws InterruptedException {
+    @Test( timeout = 5000 )
+    public void exclusiveAccess() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
-        CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
-        Thread t1 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
-        Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
+        CountDownLatch winners = new CountDownLatch( 1 ); // we expect 1 winner
+        CountDownLatch losers = new CountDownLatch( 1 ); // we expect 1 loser
+        Thread t1 = new Thread( new Access( namedLockFactory, name, false, winners, losers ) );
+        Thread t2 = new Thread( new Access( namedLockFactory, name, false, winners, losers ) );
         t1.start();
         t2.start();
         t1.join();
@@ -140,13 +168,14 @@ public abstract class NamedLockFactoryTestSupport {
         losers.await();
     }
 
-    @Test(timeout = 5000)
-    public void mixedAccess() throws InterruptedException {
+    @Test( timeout = 5000 )
+    public void mixedAccess() throws InterruptedException
+    {
         final String name = testName.getMethodName();
-        CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
-        CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
-        Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
-        Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
+        CountDownLatch winners = new CountDownLatch( 1 ); // we expect 1 winner
+        CountDownLatch losers = new CountDownLatch( 1 ); // we expect 1 loser
+        Thread t1 = new Thread( new Access( namedLockFactory, name, true, winners, losers ) );
+        Thread t2 = new Thread( new Access( namedLockFactory, name, false, winners, losers ) );
         t1.start();
         t2.start();
         t1.join();
@@ -155,18 +184,20 @@ public abstract class NamedLockFactoryTestSupport {
         losers.await();
     }
 
-    private static class Access implements Runnable {
+    private static class Access implements Runnable
+    {
         final NamedLockFactory namedLockFactory;
         final String name;
         final boolean shared;
         final CountDownLatch winner;
         final CountDownLatch loser;
 
-        public Access(NamedLockFactory namedLockFactory,
-                      String name,
-                      boolean shared,
-                      CountDownLatch winner,
-                      CountDownLatch loser) {
+        public Access( NamedLockFactory namedLockFactory,
+                       String name,
+                       boolean shared,
+                       CountDownLatch winner,
+                       CountDownLatch loser )
+        {
             this.namedLockFactory = namedLockFactory;
             this.name = name;
             this.shared = shared;
@@ -175,21 +206,32 @@ public abstract class NamedLockFactoryTestSupport {
         }
 
         @Override
-        public void run() {
-            try (NamedLock lock = namedLockFactory.getLock(name)) {
-                if (shared ? lock.lockShared(100L, TimeUnit.MILLISECONDS) : lock.lockExclusively(100L, TimeUnit.MILLISECONDS)) {
-                    try {
+        public void run()
+        {
+            try ( NamedLock lock = namedLockFactory.getLock( name ) )
+            {
+                if ( shared ? lock.lockShared( 100L, TimeUnit.MILLISECONDS ) :
+                        lock.lockExclusively( 100L, TimeUnit.MILLISECONDS ) )
+                {
+                    try
+                    {
                         winner.countDown();
                         loser.await();
-                    } finally {
+                    }
+                    finally
+                    {
                         lock.unlock();
                     }
-                } else {
+                }
+                else
+                {
                     loser.countDown();
                     winner.await();
                 }
-            } catch (InterruptedException e) {
-                Assert.fail(e.getMessage());
+            }
+            catch ( InterruptedException e )
+            {
+                Assert.fail( e.getMessage() );
             }
         }
     }
diff --git a/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast-client.xml b/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast-client.xml
index 19f1cc0..92a2fbf 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast-client.xml
+++ b/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast-client.xml
@@ -22,7 +22,7 @@
 <hazelcast-client xmlns="http://www.hazelcast.com/schema/client-config"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.hazelcast.com/schema/client-config
-                  http://www.hazelcast.com/schema/client-config/hazelcast-client-config-4.1.xsd">
+                  https://www.hazelcast.com/schema/client-config/hazelcast-client-config-5.0.xsd">
 
     <cluster-name>maven-resolver-named</cluster-name>
     <instance-name>client</instance-name>
diff --git a/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast.xml b/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast.xml
index 0c204f7..34bd1e9 100644
--- a/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast.xml
+++ b/maven-resolver-named-locks-hazelcast/src/test/resources/hazelcast.xml
@@ -22,7 +22,7 @@
 <hazelcast xmlns="http://www.hazelcast.com/schema/config"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.hazelcast.com/schema/config
-           http://www.hazelcast.com/schema/config/hazelcast-config-4.1.xsd">
+           https://www.hazelcast.com/schema/config/hazelcast-config-5.0.xsd">
 
     <cluster-name>maven-resolver-named</cluster-name>
     <instance-name>server</instance-name>
@@ -31,10 +31,22 @@
     </properties>
     <network>
         <join>
+            <auto-detection enabled="false"/>
             <multicast enabled="false"/>
             <tcp-ip>
                 <interface>localhost</interface>
             </tcp-ip>
         </join>
     </network>
+    <cp-subsystem>
+        <semaphores>
+            <!-- Config for resolver semaphores -->
+            <semaphore>
+                <name>mvn:resolver:*</name>
+                <jdk-compatible>true</jdk-compatible>
+                <!-- Integer.MAX_VALUE -->
+                <initial-permits>2147483647</initial-permits>
+            </semaphore>
+        </semaphores>
+    </cp-subsystem>
 </hazelcast>