Skip to content

Commit 3b15101

Browse files
authored
Remote repository intent (#1680)
Add new API to reflect the "intent" with given remote repository. Also, _within session_ remote repositories may be used as keys (ie in a map), but then use of new method IS MUST. (This _immediately_ revealed bug in 2.0.13: triggered #1667; not after fixes got merged)
1 parent 425fb0b commit 3b15101

File tree

4 files changed

+126
-45
lines changed

4 files changed

+126
-45
lines changed

maven-resolver-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,32 @@
3030

3131
/**
3232
* A repository on a remote server.
33+
* <p>
34+
* If use of instances of this class are meant to be used as keys, see {@link #toBareRemoteRepository()} method.
3335
*/
3436
public final class RemoteRepository implements ArtifactRepository {
37+
/**
38+
* The intent this repository is to be used for. Newly created repositories are usually "bare", and before
39+
* their actual use (caller or repository system) adapts them, equip with auth/proxy info and even mirrors, if
40+
* environment is configured for them. Note: "bare" does not always mean "without authentication", as client
41+
* code may create with all required properties, but {@link org.eclipse.aether.RepositorySystem} will process
42+
* them anyway, marking their "intent".
43+
* <p>
44+
* <em>Important consequence:</em> the change of {@link Intent} on repository may affect the use cases when
45+
* they are used as keys (they are suitable for that). To use {@link RemoteRepository} instances as key,
46+
* you should use instances returned by method {@link #toBareRemoteRepository()}, that returns "normalized"
47+
* repository instances usable as keys. Also, in "key usage case" two instances of remote repository are
48+
* considered equal if following stands: {@code Objects.equals(r1.toBareRemoteRepository(), r2.toBareRemoteRepository())}.
49+
*
50+
* @see org.eclipse.aether.RepositorySystem#newResolutionRepositories(RepositorySystemSession, List)
51+
* @see org.eclipse.aether.RepositorySystem#newDeploymentRepository(RepositorySystemSession, RemoteRepository)
52+
* @since 2.0.14
53+
*/
54+
public enum Intent {
55+
BARE,
56+
RESOLUTION,
57+
DEPLOYMENT
58+
}
3559

3660
private static final Pattern URL_PATTERN =
3761
Pattern.compile("([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*");
@@ -60,6 +84,10 @@ public final class RemoteRepository implements ArtifactRepository {
6084

6185
private final boolean blocked;
6286

87+
private final Intent intent;
88+
89+
private final int hashCode;
90+
6391
RemoteRepository(Builder builder) {
6492
if (builder.prototype != null) {
6593
id = (builder.delta & Builder.ID) != 0 ? builder.id : builder.prototype.id;
@@ -80,6 +108,7 @@ public final class RemoteRepository implements ArtifactRepository {
80108
mirroredRepositories = (builder.delta & Builder.MIRRORED) != 0
81109
? copy(builder.mirroredRepositories)
82110
: builder.prototype.mirroredRepositories;
111+
intent = (builder.delta & Builder.INTENT) != 0 ? builder.intent : builder.prototype.intent;
83112
} else {
84113
id = builder.id;
85114
type = builder.type;
@@ -91,17 +120,31 @@ public final class RemoteRepository implements ArtifactRepository {
91120
repositoryManager = builder.repositoryManager;
92121
blocked = builder.blocked;
93122
mirroredRepositories = copy(builder.mirroredRepositories);
123+
intent = builder.intent;
94124
}
95125

96126
Matcher m = URL_PATTERN.matcher(url);
97127
if (m.matches()) {
98-
protocol = m.group(1);
99-
String host = m.group(5);
100-
this.host = (host != null) ? host : "";
128+
String h = m.group(5);
129+
this.host = (h != null) ? h : "";
130+
this.protocol = m.group(1);
101131
} else {
102-
protocol = "";
103-
host = "";
132+
this.host = "";
133+
this.protocol = "";
104134
}
135+
136+
this.hashCode = Objects.hash(
137+
id,
138+
type,
139+
url, // host, protocol derived from url
140+
releasePolicy,
141+
snapshotPolicy,
142+
proxy,
143+
authentication,
144+
mirroredRepositories,
145+
repositoryManager,
146+
blocked,
147+
intent);
105148
}
106149

107150
private static List<RemoteRepository> copy(List<RemoteRepository> repos) {
@@ -111,10 +154,12 @@ private static List<RemoteRepository> copy(List<RemoteRepository> repos) {
111154
return Collections.unmodifiableList(Arrays.asList(repos.toArray(new RemoteRepository[0])));
112155
}
113156

157+
@Override
114158
public String getId() {
115159
return id;
116160
}
117161

162+
@Override
118163
public String getContentType() {
119164
return type;
120165
}
@@ -203,6 +248,16 @@ public boolean isBlocked() {
203248
return blocked;
204249
}
205250

251+
/**
252+
* Returns the intent this repository is prepared for.
253+
*
254+
* @return The intent this repository is prepared for.
255+
* @since 2.0.14
256+
*/
257+
public Intent getIntent() {
258+
return intent;
259+
}
260+
206261
@Override
207262
public String toString() {
208263
StringBuilder buffer = new StringBuilder(256);
@@ -225,6 +280,7 @@ public String toString() {
225280
if (isBlocked()) {
226281
buffer.append(", blocked");
227282
}
283+
buffer.append(", ").append(getIntent().name()).append(")");
228284
buffer.append(")");
229285
return buffer.toString();
230286
}
@@ -248,26 +304,39 @@ public boolean equals(Object obj) {
248304
&& Objects.equals(proxy, that.proxy)
249305
&& Objects.equals(authentication, that.authentication)
250306
&& Objects.equals(mirroredRepositories, that.mirroredRepositories)
251-
&& repositoryManager == that.repositoryManager;
307+
&& repositoryManager == that.repositoryManager
308+
&& blocked == that.blocked
309+
&& intent == that.intent;
252310
}
253311

254312
@Override
255313
public int hashCode() {
256-
int hash = 17;
257-
hash = hash * 31 + hash(url);
258-
hash = hash * 31 + hash(type);
259-
hash = hash * 31 + hash(id);
260-
hash = hash * 31 + hash(releasePolicy);
261-
hash = hash * 31 + hash(snapshotPolicy);
262-
hash = hash * 31 + hash(proxy);
263-
hash = hash * 31 + hash(authentication);
264-
hash = hash * 31 + hash(mirroredRepositories);
265-
hash = hash * 31 + (repositoryManager ? 1 : 0);
266-
return hash;
314+
return hashCode;
267315
}
268316

269-
private static int hash(Object obj) {
270-
return obj != null ? obj.hashCode() : 0;
317+
/**
318+
* Makes "bare" repository out of this instance, usable as keys within one single session, by applying following
319+
* changes to repository (returns new instance):
320+
* <ul>
321+
* <li>sets intent to {@link Intent#BARE}</li>
322+
* <li>nullifies proxy</li>
323+
* <li>nullifies authentication</li>
324+
* <li>nullifies mirrors</li>
325+
* <li>sets repositoryManager to {@code false}</li>
326+
* </ul>
327+
* These properties are managed by repository system, based on configuration. See {@link org.eclipse.aether.RepositorySystem}
328+
* and (internal component) {@code org.eclipse.aether.impl.RemoteRepositoryManager}.
329+
*
330+
* @since 2.0.14
331+
*/
332+
public RemoteRepository toBareRemoteRepository() {
333+
return new Builder(this)
334+
.setIntent(Intent.BARE)
335+
.setProxy(null)
336+
.setAuthentication(null)
337+
.setMirroredRepositories(null)
338+
.setRepositoryManager(false)
339+
.build();
271340
}
272341

273342
/**
@@ -286,7 +355,8 @@ public static final class Builder {
286355
AUTH = 0x0040,
287356
MIRRORED = 0x0080,
288357
REPOMAN = 0x0100,
289-
BLOCKED = 0x0200;
358+
BLOCKED = 0x0200,
359+
INTENT = 0x0400;
290360

291361
int delta;
292362

@@ -312,6 +382,8 @@ public static final class Builder {
312382

313383
boolean blocked;
314384

385+
Intent intent = Intent.BARE;
386+
315387
/**
316388
* Creates a new repository builder.
317389
*
@@ -545,5 +617,20 @@ public Builder setBlocked(boolean blocked) {
545617
}
546618
return this;
547619
}
620+
621+
/**
622+
* Marks the intent for this repository.
623+
*
624+
* @param intent the intent with this remote repository.
625+
* @return This builder for chaining, never {@code null}.
626+
* @since 2.0.14
627+
*/
628+
public Builder setIntent(Intent intent) {
629+
this.intent = intent;
630+
if (prototype != null) {
631+
delta(INTENT, this.intent, prototype.intent);
632+
}
633+
return this;
634+
}
548635
}
549636
}

maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Arrays;
2727
import java.util.List;
2828
import java.util.ListIterator;
29+
import java.util.stream.Collectors;
2930

3031
import org.eclipse.aether.RepositoryCache;
3132
import org.eclipse.aether.RepositorySystemSession;
@@ -160,7 +161,11 @@ public List<RemoteRepository> aggregateRepositories(
160161
result.add(repository);
161162
}
162163

163-
return result;
164+
return result.stream()
165+
.map(r -> new RemoteRepository.Builder(r)
166+
.setIntent(RemoteRepository.Intent.RESOLUTION)
167+
.build())
168+
.collect(Collectors.toList());
164169
}
165170

166171
private void logMirror(RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror) {

maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -441,21 +441,23 @@ public List<RemoteRepository> newResolutionRepositories(
441441
validateSession(session);
442442
validateRepositories(repositories);
443443
repositorySystemValidator.validateRemoteRepositories(session, repositories);
444-
repositories = remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true);
445-
return repositories;
444+
445+
return remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true);
446446
}
447447

448448
@Override
449449
public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) {
450450
validateSession(session);
451451
requireNonNull(repository, "repository cannot be null");
452452
repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository));
453-
RemoteRepository.Builder builder = new RemoteRepository.Builder(repository);
453+
454454
Authentication auth = session.getAuthenticationSelector().getAuthentication(repository);
455-
builder.setAuthentication(auth);
456455
Proxy proxy = session.getProxySelector().getProxy(repository);
457-
builder.setProxy(proxy);
458-
return builder.build();
456+
return new RemoteRepository.Builder(repository)
457+
.setAuthentication(auth)
458+
.setProxy(proxy)
459+
.setIntent(RemoteRepository.Intent.DEPLOYMENT)
460+
.build();
459461
}
460462

461463
@Override

maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/RemoteRepositoryFilterSourceSupport.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.io.IOException;
2222
import java.io.UncheckedIOException;
2323
import java.nio.file.Path;
24-
import java.util.List;
2524

2625
import org.eclipse.aether.ConfigurationProperties;
2726
import org.eclipse.aether.RepositorySystemSession;
@@ -79,26 +78,14 @@ protected Path getBasedir(
7978
}
8079

8180
/**
82-
* We use remote repositories as keys, but they may fly in as "bare" or as "equipped" (w/ auth and proxy) if caller
83-
* used {@link org.eclipse.aether.RepositorySystem#newResolutionRepositories(RepositorySystemSession, List)} beforehand.
84-
* The hash/equalTo method factors in all these as well, but from our perspective, they do not matter. So we make all
85-
* key remote repositories back to "bare".
86-
* Ignored properties of normalized repositories:
87-
* <ul>
88-
* <li>proxy - is environment dependent</li>
89-
* <li>authentication - is environment and/or user dependent</li>
90-
* <li>mirrored repositories - is environment dependent (within same session does not change)</li>
91-
* <li>repository manager - is environment dependent (within same session does not change)</li>
92-
* </ul>
81+
* We use remote repositories as keys, so normalize them.
82+
*
83+
* @since 2.0.14
84+
* @see RemoteRepository#toBareRemoteRepository()
9385
*/
9486
protected RemoteRepository normalizeRemoteRepository(
9587
RepositorySystemSession session, RemoteRepository remoteRepository) {
96-
return new RemoteRepository.Builder(remoteRepository)
97-
.setProxy(null)
98-
.setAuthentication(null)
99-
.setMirroredRepositories(null)
100-
.setRepositoryManager(false)
101-
.build();
88+
return remoteRepository.toBareRemoteRepository();
10289
}
10390

10491
/**

0 commit comments

Comments
 (0)