diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java index 63e8394bf..d9d0bfd45 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java @@ -61,12 +61,39 @@ public interface SyncContext extends Closeable { * * @param artifacts The artifacts to acquire, may be {@code null} or empty if none. * @param metadatas The metadatas to acquire, may be {@code null} or empty if none. + * @throws FailedToAcquireLockException if method calls to acquire lock within configured time. */ - void acquire(Collection artifacts, Collection metadatas); + void acquire(Collection artifacts, Collection metadatas) + throws FailedToAcquireLockException; /** * Releases all previously acquired artifacts/metadatas. If no resources have been acquired before or if this * synchronization context has already been closed, this method does nothing. */ + @Override void close(); + + /** + * Specific exception thrown by {@link #acquire(Collection, Collection)} method when it cannot acquire the lock. + * + * @since 1.9.25 + */ + final class FailedToAcquireLockException extends IllegalStateException { + private final boolean shared; + + /** + * Constructor. + */ + public FailedToAcquireLockException(boolean shared, String message) { + super(message); + this.shared = shared; + } + + /** + * Returns {@code true} for shared and {@code false} for exclusive sync contexts. + */ + public boolean isShared() { + return shared; + } + } } 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 7a608c95d..20d6132ec 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 @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Deque; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.SyncContext; @@ -32,6 +33,7 @@ import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.named.providers.FileLockNamedLockFactory; import org.eclipse.aether.util.ConfigUtils; +import org.eclipse.aether.util.artifact.ArtifactIdUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +45,7 @@ public final class NamedLockFactoryAdapter { public static final String TIME_KEY = "aether.syncContext.named.time"; - public static final long DEFAULT_TIME = 30L; + public static final long DEFAULT_TIME = 900L; public static final String TIME_UNIT_KEY = "aether.syncContext.named.time.unit"; @@ -216,12 +218,50 @@ public void acquire(Collection artifacts, Collection artifacts, Collection metadatas) { + StringBuilder builder = new StringBuilder(); + if (artifacts != null && !artifacts.isEmpty()) { + builder.append("artifacts: ") + .append(artifacts.stream().map(ArtifactIdUtils::toId).collect(Collectors.joining(", "))); + } + if (metadatas != null && !metadatas.isEmpty()) { + if (builder.length() != 0) { + builder.append("; "); + } + builder.append("metadata: ") + .append(metadatas.stream().map(this::metadataSubjects).collect(Collectors.joining(", "))); + } + return builder.toString(); + } + + private String metadataSubjects(Metadata metadata) { + String name = ""; + if (!metadata.getGroupId().isEmpty()) { + name += metadata.getGroupId(); + if (!metadata.getArtifactId().isEmpty()) { + name += ":" + metadata.getArtifactId(); + if (!metadata.getVersion().isEmpty()) { + name += ":" + metadata.getVersion(); + } + } + } + if (!metadata.getType().isEmpty()) { + name += (name.isEmpty() ? "" : ":") + metadata.getType(); + } + return name; + } + private void closeAll() { if (locks.isEmpty()) { return; diff --git a/src/site/markdown/configuration.md b/src/site/markdown/configuration.md index 83db98530..6669adba3 100644 --- a/src/site/markdown/configuration.md +++ b/src/site/markdown/configuration.md @@ -103,7 +103,7 @@ under the License. | `aether.syncContext.named.nameMapper` | String | Name of name mapper implementing the `org.eclipse.aether.internal.impl.synccontext.named.NameMapper` interface. | `"gav"` | no | | `aether.syncContext.named.retry` | int | Count of retries SyncContext adapter should perform, when obtaining locks. | `1` | no | | `aether.syncContext.named.retry.wait` | long | Amount of milliseconds a thread to wait between retries, when obtaining locks. | `200` | no | -| `aether.syncContext.named.time` | long | Amount of time a synchronization context shall wait to obtain a lock. | `30` | no | +| `aether.syncContext.named.time` | long | Amount of time a synchronization context shall wait to obtain a lock. | `900` | no | | `aether.syncContext.named.time.unit` | long | Unit of the lock wait time. | `"SECONDS"` | no | | `aether.syncContext.named.discriminating.discriminator` | String | A discriminator name prefix identifying a Resolver instance. | `"sha1('${hostname:-localhost}:${maven.repo.local}')"` or `"sha1('')"` if generation fails | no | | `aether.syncContext.named.discriminating.hostname` | String | The hostname to be used with discriminating mapper. | Detected with `InetAddress.getLocalHost().getHostName()` | no |