diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java index 12ef0d696..292a45d0e 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java @@ -70,6 +70,7 @@ import org.eclipse.aether.spi.io.FileProcessor; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextHint; import org.eclipse.aether.transfer.ArtifactNotFoundException; import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; @@ -214,21 +215,29 @@ public List resolveArtifacts( RepositorySystemSession session, throws ArtifactResolutionException { - try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) + SyncContextHint.SCOPE.set( SyncContextHint.Scope.RESOLVE ); // HACK + try { - Collection artifacts = new ArrayList<>( requests.size() ); - for ( ArtifactRequest request : requests ) + try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) { - if ( request.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) + Collection artifacts = new ArrayList<>( requests.size() ); + for ( ArtifactRequest request : requests ) { - continue; + if ( request.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null ) != null ) + { + continue; + } + artifacts.add( request.getArtifact() ); } - artifacts.add( request.getArtifact() ); - } - syncContext.acquire( artifacts, null ); + syncContext.acquire( artifacts, null ); - return resolve( session, requests ); + return resolve( session, requests ); + } + } + finally + { + SyncContextHint.SCOPE.set( null ); } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java index cd217b512..7c4dba79b 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java @@ -66,6 +66,7 @@ import org.eclipse.aether.spi.connector.RepositoryConnector; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextHint; import org.eclipse.aether.transfer.MetadataNotFoundException; import org.eclipse.aether.transfer.MetadataTransferException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; @@ -170,17 +171,25 @@ public List resolveMetadata( RepositorySystemSession session, Collection requests ) { - try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) + SyncContextHint.SCOPE.set( SyncContextHint.Scope.RESOLVE ); // HACK + try { - Collection metadata = new ArrayList<>( requests.size() ); - for ( MetadataRequest request : requests ) + try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) { - metadata.add( request.getMetadata() ); - } + Collection metadata = new ArrayList<>( requests.size() ); + for ( MetadataRequest request : requests ) + { + metadata.add( request.getMetadata() ); + } - syncContext.acquire( null, metadata ); + syncContext.acquire( null, metadata ); - return resolve( session, requests ); + return resolve( session, requests ); + } + } + finally + { + SyncContextHint.SCOPE.set( null ); // HACK } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java index ba47c8d45..38f8bed15 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/NamedSyncContextFactory.java @@ -25,6 +25,7 @@ import org.eclipse.aether.internal.impl.synccontext.named.GAVNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; +import org.eclipse.aether.internal.impl.synccontext.named.ResolverLockFactory; import org.eclipse.aether.internal.impl.synccontext.named.StaticNameMapper; import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory; @@ -107,7 +108,7 @@ private static NamedLockFactoryAdapter selectAndAdapt( final Map * The default setup wraps {@link GAVNameMapper}, but manually may be created any instance needed. */ @@ -84,13 +81,17 @@ public DiscriminatingNameMapper( @Named( GAVNameMapper.NAME ) final NameMapper n } @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, final Artifact artifact ) + { + String discriminator = createDiscriminator( session ); + return discriminator + ":" + nameMapper.nameLock( session, artifact ); + } + + @Override + public String nameLock( final RepositorySystemSession session, Metadata metadata ) { String discriminator = createDiscriminator( session ); - return nameMapper.nameLocks( session, artifacts, metadatas ).stream().map( s -> discriminator + ":" + s ) - .collect( toList() ); + return discriminator + ":" + nameMapper.nameLock( session, metadata ); } private String getHostname() diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java index ea0149c47..6cebb407e 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper.java @@ -25,8 +25,6 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.Collection; -import java.util.TreeSet; /** * Artifact GAV {@link NameMapper}, uses artifact and metadata coordinates to name their corresponding locks. Is not @@ -39,44 +37,29 @@ public class GAVNameMapper implements NameMapper public static final String NAME = "gav"; @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, final Artifact artifact ) { - // Deadlock prevention: https://stackoverflow.com/a/16780988/696632 - // We must acquire multiple locks always in the same order! - Collection keys = new TreeSet<>(); - if ( artifacts != null ) - { - for ( Artifact artifact : artifacts ) - { - String key = "artifact:" + artifact.getGroupId() - + ":" + artifact.getArtifactId() - + ":" + artifact.getBaseVersion(); - keys.add( key ); - } - } + return "artifact:" + artifact.getGroupId() + + ":" + artifact.getArtifactId() + + ":" + artifact.getBaseVersion(); + } - if ( metadatas != null ) + @Override + public String nameLock( final RepositorySystemSession session, final Metadata metadata ) + { + StringBuilder key = new StringBuilder( "metadata:" ); + if ( !metadata.getGroupId().isEmpty() ) { - for ( Metadata metadata : metadatas ) + key.append( metadata.getGroupId() ); + if ( !metadata.getArtifactId().isEmpty() ) { - StringBuilder key = new StringBuilder( "metadata:" ); - if ( !metadata.getGroupId().isEmpty() ) + key.append( ':' ).append( metadata.getArtifactId() ); + if ( !metadata.getVersion().isEmpty() ) { - key.append( metadata.getGroupId() ); - if ( !metadata.getArtifactId().isEmpty() ) - { - key.append( ':' ).append( metadata.getArtifactId() ); - if ( !metadata.getVersion().isEmpty() ) - { - key.append( ':' ).append( metadata.getVersion() ); - } - } + key.append( ':' ).append( metadata.getVersion() ); } - keys.add( key.toString() ); } } - return keys; + return key.toString(); } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java index b5fd2f0e5..89ff3f1c3 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NameMapper.java @@ -23,8 +23,6 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.metadata.Metadata; -import java.util.Collection; - /** * Component mapping lock names to passed in artifacts and metadata as required. */ @@ -37,6 +35,7 @@ public interface NameMapper * same criteria) to avoid deadlocks by acquiring locks in same order, essentially disregarding the order of * the input collections. */ - Collection nameLocks( RepositorySystemSession session, Collection artifacts, - Collection metadatas ); + String nameLock( RepositorySystemSession session, Artifact artifact ); + + String nameLock( RepositorySystemSession session, Metadata metadata ); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java index 6fb68d31f..beb77fcd9 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter.java @@ -39,19 +39,16 @@ */ public final class NamedLockFactoryAdapter { - private final NameMapper nameMapper; - - private final NamedLockFactory namedLockFactory; + private final ResolverLockFactory resolverLockFactory; private final long time; private final TimeUnit timeUnit; - public NamedLockFactoryAdapter( final NameMapper nameMapper, final NamedLockFactory namedLockFactory, + public NamedLockFactoryAdapter( final ResolverLockFactory resolverLockFactory, final long time, final TimeUnit timeUnit ) { - this.nameMapper = Objects.requireNonNull( nameMapper ); - this.namedLockFactory = Objects.requireNonNull( namedLockFactory ); + this.resolverLockFactory = resolverLockFactory; if ( time < 0L ) { throw new IllegalArgumentException( "time cannot be negative" ); @@ -62,12 +59,12 @@ public NamedLockFactoryAdapter( final NameMapper nameMapper, final NamedLockFact public SyncContext newInstance( final RepositorySystemSession session, final boolean shared ) { - return new AdaptedLockSyncContext( session, shared, nameMapper, namedLockFactory, time, timeUnit ); + return new AdaptedLockSyncContext( session, shared, resolverLockFactory, time, timeUnit ); } public void shutdown() { - namedLockFactory.shutdown(); + resolverLockFactory.shutdown(); } private static class AdaptedLockSyncContext implements SyncContext @@ -78,28 +75,21 @@ private static class AdaptedLockSyncContext implements SyncContext private final boolean shared; - private final NameMapper lockNaming; - - private final SessionAwareNamedLockFactory sessionAwareNamedLockFactory; - - private final NamedLockFactory namedLockFactory; + private final ResolverLockFactory resolverLockFactory; private final long time; private final TimeUnit timeUnit; - private final Deque locks; + private final Deque locks; private AdaptedLockSyncContext( final RepositorySystemSession session, final boolean shared, - final NameMapper lockNaming, final NamedLockFactory namedLockFactory, + final ResolverLockFactory resolverLockFactory, final long time, final TimeUnit timeUnit ) { this.session = session; this.shared = shared; - this.lockNaming = lockNaming; - this.sessionAwareNamedLockFactory = namedLockFactory instanceof SessionAwareNamedLockFactory - ? (SessionAwareNamedLockFactory) namedLockFactory : null; - this.namedLockFactory = namedLockFactory; + this.resolverLockFactory = resolverLockFactory; this.time = time; this.timeUnit = timeUnit; this.locks = new ArrayDeque<>(); @@ -108,45 +98,35 @@ private AdaptedLockSyncContext( final RepositorySystemSession session, final boo @Override public void acquire( Collection artifacts, Collection metadatas ) { - Collection keys = lockNaming.nameLocks( session, artifacts, metadatas ); - if ( keys.isEmpty() ) + Collection resolverLocks = resolverLockFactory.resolverLocks( + session, shared, artifacts, metadatas ); + if ( resolverLocks.isEmpty() ) { return; } - LOGGER.trace( "Need {} {} lock(s) for {}", keys.size(), shared ? "read" : "write", keys ); + LOGGER.trace( "Need {} {} lock(s) for {}", resolverLocks.size(), shared ? "read" : "write", resolverLocks ); int acquiredLockCount = 0; - for ( String key : keys ) + for ( ResolverLock resolverLock : resolverLocks ) { - NamedLock namedLock = sessionAwareNamedLockFactory != null ? sessionAwareNamedLockFactory - .getLock( session, key ) : namedLockFactory.getLock( key ); try { - LOGGER.trace( "Acquiring {} lock for '{}'", - shared ? "read" : "write", key ); - - boolean locked; - if ( shared ) - { - locked = namedLock.lockShared( time, timeUnit ); - } - else - { - locked = namedLock.lockExclusively( time, timeUnit ); - } + LOGGER.trace( "Acquiring effective {} lock for '{}'", + resolverLock.isEffectiveShared() ? "read" : "write", resolverLock.key() ); + boolean locked = resolverLock.tryLock( time, timeUnit ); if ( !locked ) { - LOGGER.trace( "Failed to acquire {} lock for '{}'", - shared ? "read" : "write", key ); + LOGGER.trace( "Failed to acquire effective {} lock for '{}'", + resolverLock.isEffectiveShared() ? "read" : "write", resolverLock.key() ); - namedLock.close(); + resolverLock.close(); throw new IllegalStateException( - "Could not acquire " + ( shared ? "read" : "write" ) - + " lock for '" + namedLock.name() + "'" ); + "Could not acquire effective " + ( resolverLock.isEffectiveShared() ? "read" : "write" ) + + " lock for '" + resolverLock.key() + "'" ); } - locks.push( namedLock ); + locks.push( resolverLock ); acquiredLockCount++; } catch ( InterruptedException e ) @@ -170,11 +150,11 @@ public void close() int released = 0; while ( !locks.isEmpty() ) { - try ( NamedLock namedLock = locks.pop() ) + try ( ResolverLock resolverLock = locks.pop() ) { LOGGER.trace( "Releasing {} lock for '{}'", - shared ? "read" : "write", namedLock.name() ); - namedLock.unlock(); + shared ? "read" : "write", resolverLock.key() ); + resolverLock.unlock(); released++; } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java new file mode 100644 index 000000000..89b26b868 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLock.java @@ -0,0 +1,122 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.eclipse.aether.named.NamedLock; + +import java.io.Closeable; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * Resolver lock. + */ +public final class ResolverLock implements Closeable +{ + private final String key; + + private final NamedLock namedLock; + + private final boolean requestedShared; + + private final boolean effectiveShared; + + public ResolverLock( final String key, + final NamedLock namedLock, + final boolean requestedShared, + final boolean effectiveShared ) + { + this.key = Objects.requireNonNull( key ); + this.namedLock = Objects.requireNonNull( namedLock ); + this.requestedShared = requestedShared; + this.effectiveShared = effectiveShared; + } + + public String key() + { + return key; + } + + public boolean isRequestedShared() + { + return requestedShared; + } + + public boolean isEffectiveShared() + { + return effectiveShared; + } + + public boolean tryLock( final long time, final TimeUnit unit ) throws InterruptedException + { + if ( effectiveShared ) + { + return namedLock.lockShared( time, unit ); + } + else + { + return namedLock.lockExclusively( time, unit ); + } + } + + public void unlock() + { + namedLock.unlock(); + } + + @Override + public void close() + { + namedLock.close(); + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + ResolverLock that = (ResolverLock) o; + return key.equals( that.key ); + } + + @Override + public int hashCode() + { + return Objects.hash( key ); + } + + @Override + public String toString() + { + return getClass().getSimpleName() + + "{" + + "key='" + key + '\'' + + ", namedLock=" + namedLock + + ", requestedShared=" + requestedShared + + ", effectiveShared=" + effectiveShared + + '}'; + } +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java new file mode 100644 index 000000000..f1189ef7a --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ResolverLockFactory.java @@ -0,0 +1,112 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.named.NamedLock; +import org.eclipse.aether.named.NamedLockFactory; +import org.eclipse.aether.repository.LocalArtifactRequest; +import org.eclipse.aether.repository.LocalArtifactResult; +import org.eclipse.aether.repository.LocalMetadataRequest; +import org.eclipse.aether.repository.LocalMetadataResult; +import org.eclipse.aether.spi.synccontext.SyncContextHint; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Objects; +import java.util.TreeSet; + +/** + * Component mapping lock names to passed in artifacts and metadata as required. + */ +public final class ResolverLockFactory +{ + private final NameMapper nameMapper; + + private final NamedLockFactory namedLockFactory; + + public ResolverLockFactory( final NameMapper nameMapper, final NamedLockFactory namedLockFactory ) + { + this.nameMapper = Objects.requireNonNull( nameMapper ); + this.namedLockFactory = Objects.requireNonNull( namedLockFactory ); + } + + public Collection resolverLocks( final RepositorySystemSession session, + final boolean shared, + final Collection artifacts, + final Collection metadatas ) + { + TreeSet result = new TreeSet<>( Comparator.comparing( ResolverLock::key ) ); + boolean effectiveShared = shared; + boolean mayOverride = SyncContextHint.Scope.RESOLVE.equals( SyncContextHint.SCOPE.get() ); + + if ( artifacts != null ) + { + for ( Artifact artifact : artifacts ) + { + NamedLock namedLock = namedLockFactory.getLock( nameMapper.nameLock( session, artifact ) ); + if ( mayOverride && !shared ) + { + effectiveShared = isArtifactAvailable( session, artifact ); + } + result.add( new ResolverLock( artifact.toString(), namedLock, shared, effectiveShared ) ); + } + } + + if ( metadatas != null ) + { + for ( Metadata metadata : metadatas ) + { + NamedLock namedLock = namedLockFactory.getLock( nameMapper.nameLock( session, metadata ) ); + if ( mayOverride && !shared ) + { + effectiveShared = isMetadataAvailable( session, metadata ); + } + result.add( new ResolverLock( metadata.toString(), namedLock, shared, effectiveShared ) ); + } + } + + return result; + } + + private boolean isArtifactAvailable( final RepositorySystemSession session, final Artifact artifact ) + { + LocalArtifactRequest request = new LocalArtifactRequest( artifact, null, null ); + LocalArtifactResult result = session.getLocalRepositoryManager().find( session, request ); + return result.getFile() != null; + } + + private boolean isMetadataAvailable( final RepositorySystemSession session, final Metadata metadata ) + { + LocalMetadataRequest request = new LocalMetadataRequest( metadata, null, null ); + LocalMetadataResult result = session.getLocalRepositoryManager().find( session, request ); + return result.getFile() != null; + } + + /** + * Performs a clean shut down of the factory. + */ + public void shutdown() + { + namedLockFactory.shutdown(); + } +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java index 14fc7e79a..1cb498c12 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/StaticNameMapper.java @@ -27,8 +27,6 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import java.util.Collection; -import java.util.Collections; import java.util.Objects; /** @@ -65,10 +63,14 @@ public StaticNameMapper( final String name ) } @Override - public Collection nameLocks( final RepositorySystemSession session, - final Collection artifacts, - final Collection metadatas ) + public String nameLock( final RepositorySystemSession session, Artifact artifact ) { - return Collections.singletonList( ConfigUtils.getString( session, name, CONFIG_PROP_NAME ) ); + return ConfigUtils.getString( session, name, CONFIG_PROP_NAME ); + } + + @Override + public String nameLock( final RepositorySystemSession session, Metadata metadata ) + { + return ConfigUtils.getString( session, name, CONFIG_PROP_NAME ); } } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java index 87cab6f86..4acf1fccd 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java @@ -67,7 +67,7 @@ public abstract class NamedLockFactoryAdapterTestSupport { public static void createAdapter() { Objects.requireNonNull(namedLockFactory, "NamedLockFactory not set"); - adapter = new NamedLockFactoryAdapter(nameMapper, namedLockFactory, ADAPTER_TIME, ADAPTER_TIME_UNIT); + adapter = new NamedLockFactoryAdapter(new ResolverLockFactory( nameMapper, namedLockFactory ), ADAPTER_TIME, ADAPTER_TIME_UNIT); } @AfterClass 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 7fc824179..5471ff715 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 @@ -25,6 +25,7 @@ import org.eclipse.aether.internal.impl.synccontext.named.DiscriminatingNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.GAVNameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; +import org.eclipse.aether.internal.impl.synccontext.named.ResolverLockFactory; import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.spi.synccontext.SyncContextFactory; @@ -62,7 +63,8 @@ public abstract class NamedLockFactoryAdapterTestSupport protected static void setNamedLockFactory(final NamedLockFactory namedLockFactory) { adapter = new NamedLockFactoryAdapter( - new DiscriminatingNameMapper(new GAVNameMapper()), namedLockFactory, ADAPTER_TIME, ADAPTER_TIME_UNIT + new ResolverLockFactory( new DiscriminatingNameMapper(new GAVNameMapper()), namedLockFactory ), + ADAPTER_TIME, ADAPTER_TIME_UNIT ); } diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java new file mode 100644 index 000000000..2904703fe --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/synccontext/SyncContextHint.java @@ -0,0 +1,36 @@ +package org.eclipse.aether.spi.synccontext; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Hint for sync scope implemented as "hack" to not modify SyncContextFactory API. + */ +public final class SyncContextHint +{ + /** + * The scope for which {@link org.eclipse.aether.SyncContext} is to be used. + */ + public enum Scope + { + RESOLVE, DEPLOY, INSTALL + } + + public static final InheritableThreadLocal SCOPE = new InheritableThreadLocal<>(); +}