Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas);
void acquire(Collection<? extends Artifact> artifacts, Collection<? extends Metadata> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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";

Expand Down Expand Up @@ -216,12 +218,50 @@ public void acquire(Collection<? extends Artifact> artifacts, Collection<? exten
}
}
if (!illegalStateExceptions.isEmpty()) {
IllegalStateException ex = new IllegalStateException("Could not acquire lock(s)");
String message = "Could not acquire " + (shared ? "shared" : "exclusive") + " lock for "
+ lockSubjects(artifacts, metadatas) + " in " + time + " " + timeUnit
+ "; consider using '" + TIME_KEY
+ "' property to increase lock timeout to a value that fits your environment";
FailedToAcquireLockException ex = new FailedToAcquireLockException(shared, message);
illegalStateExceptions.forEach(ex::addSuppressed);
throw namedLockFactory.onFailure(ex);
}
}

private String lockSubjects(
Collection<? extends Artifact> artifacts, Collection<? extends Metadata> 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;
Expand Down
2 changes: 1 addition & 1 deletion src/site/markdown/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down