1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl.scope;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Comparator;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Set;
30 import java.util.concurrent.atomic.AtomicReference;
31 import java.util.stream.Collectors;
32
33 import org.eclipse.aether.RepositorySystemSession;
34 import org.eclipse.aether.artifact.Artifact;
35 import org.eclipse.aether.collection.CollectResult;
36 import org.eclipse.aether.collection.DependencySelector;
37 import org.eclipse.aether.graph.DependencyFilter;
38 import org.eclipse.aether.impl.scope.BuildPath;
39 import org.eclipse.aether.impl.scope.BuildScope;
40 import org.eclipse.aether.impl.scope.BuildScopeQuery;
41 import org.eclipse.aether.impl.scope.BuildScopeSource;
42 import org.eclipse.aether.impl.scope.InternalScopeManager;
43 import org.eclipse.aether.impl.scope.ProjectPath;
44 import org.eclipse.aether.impl.scope.ScopeManagerConfiguration;
45 import org.eclipse.aether.scope.DependencyScope;
46 import org.eclipse.aether.scope.ResolutionScope;
47 import org.eclipse.aether.scope.SystemDependencyScope;
48 import org.eclipse.aether.util.filter.ScopeDependencyFilter;
49 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
50 import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
51 import org.eclipse.aether.util.graph.visitor.CloningDependencyVisitor;
52 import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor;
53
54 import static java.util.Objects.requireNonNull;
55
56 public final class ScopeManagerImpl implements InternalScopeManager {
57 private final String id;
58 private final boolean strictDependencyScopes;
59 private final boolean strictResolutionScopes;
60 private final BuildScopeSource buildScopeSource;
61 private final AtomicReference<SystemDependencyScopeImpl> systemDependencyScope;
62 private final Map<String, DependencyScopeImpl> dependencyScopes;
63 private final Collection<DependencyScope> dependencyScopesUniverse;
64 private final Map<String, ResolutionScopeImpl> resolutionScopes;
65 private final Collection<ResolutionScope> resolutionScopesUniverse;
66
67 public ScopeManagerImpl(ScopeManagerConfiguration configuration) {
68 this.id = configuration.getId();
69 this.strictDependencyScopes = configuration.isStrictDependencyScopes();
70 this.strictResolutionScopes = configuration.isStrictResolutionScopes();
71 this.buildScopeSource = configuration.getBuildScopeSource();
72 this.systemDependencyScope = new AtomicReference<>(null);
73 this.dependencyScopes = Collections.unmodifiableMap(buildDependencyScopes(configuration));
74 this.dependencyScopesUniverse = Collections.unmodifiableCollection(new HashSet<>(dependencyScopes.values()));
75 this.resolutionScopes = Collections.unmodifiableMap(buildResolutionScopes(configuration));
76 this.resolutionScopesUniverse = Collections.unmodifiableCollection(new HashSet<>(resolutionScopes.values()));
77 }
78
79 private Map<String, DependencyScopeImpl> buildDependencyScopes(ScopeManagerConfiguration configuration) {
80 Collection<DependencyScope> dependencyScopes = configuration.buildDependencyScopes(this);
81 HashMap<String, DependencyScopeImpl> result = new HashMap<>(dependencyScopes.size());
82 dependencyScopes.forEach(d -> result.put(d.getId(), (DependencyScopeImpl) d));
83 return result;
84 }
85
86 private Map<String, ResolutionScopeImpl> buildResolutionScopes(ScopeManagerConfiguration configuration) {
87 Collection<ResolutionScope> resolutionScopes = configuration.buildResolutionScopes(this);
88 HashMap<String, ResolutionScopeImpl> result = new HashMap<>(resolutionScopes.size());
89 resolutionScopes.forEach(r -> result.put(r.getId(), (ResolutionScopeImpl) r));
90 return result;
91 }
92
93 @Override
94 public String getId() {
95 return id;
96 }
97
98 @Override
99 public Optional<SystemDependencyScope> getSystemDependencyScope() {
100 return Optional.ofNullable(systemDependencyScope.get());
101 }
102
103 @Override
104 public Optional<DependencyScope> getDependencyScope(String id) {
105 DependencyScope dependencyScope = dependencyScopes.get(id);
106 if (strictDependencyScopes && dependencyScope == null) {
107 throw new IllegalArgumentException("unknown dependency scope");
108 }
109 return Optional.ofNullable(dependencyScope);
110 }
111
112 @Override
113 public Collection<DependencyScope> getDependencyScopeUniverse() {
114 return dependencyScopesUniverse;
115 }
116
117 @Override
118 public Optional<ResolutionScope> getResolutionScope(String id) {
119 ResolutionScope resolutionScope = resolutionScopes.get(id);
120 if (strictResolutionScopes && resolutionScope == null) {
121 throw new IllegalArgumentException("unknown resolution scope");
122 }
123 return Optional.ofNullable(resolutionScope);
124 }
125
126 @Override
127 public Collection<ResolutionScope> getResolutionScopeUniverse() {
128 return resolutionScopesUniverse;
129 }
130
131 @Override
132 public int getDependencyScopeWidth(DependencyScope dependencyScope) {
133 return translate(dependencyScope).getWidth();
134 }
135
136 @Override
137 public Optional<BuildScope> getDependencyScopeMainProjectBuildScope(DependencyScope dependencyScope) {
138 return Optional.ofNullable(translate(dependencyScope).getMainBuildScope());
139 }
140
141 @Override
142 public DependencySelector getDependencySelector(RepositorySystemSession session, ResolutionScope resolutionScope) {
143 ResolutionScopeImpl rs = translate(resolutionScope);
144 Set<String> directlyExcludedLabels = getDirectlyExcludedLabels(rs);
145 Set<String> transitivelyExcludedLabels = getTransitivelyExcludedLabels(rs);
146 if (session.getDependencySelector() != null) {
147 return new AndDependencySelector(
148 rs.getMode() == Mode.ELIMINATE
149 ? ScopeDependencySelector.fromTo(2, 2, null, directlyExcludedLabels)
150 : ScopeDependencySelector.fromTo(1, 2, null, directlyExcludedLabels),
151 ScopeDependencySelector.from(2, null, transitivelyExcludedLabels),
152 OptionalDependencySelector.fromDirect(),
153 new ExclusionDependencySelector(),
154 session.getDependencySelector());
155 } else {
156 return new AndDependencySelector(
157 rs.getMode() == Mode.ELIMINATE
158 ? ScopeDependencySelector.fromTo(2, 2, null, directlyExcludedLabels)
159 : ScopeDependencySelector.fromTo(1, 2, null, directlyExcludedLabels),
160 ScopeDependencySelector.from(2, null, transitivelyExcludedLabels),
161 OptionalDependencySelector.fromDirect(),
162 new ExclusionDependencySelector());
163 }
164 }
165
166 @Override
167 public DependencyFilter getDependencyFilter(RepositorySystemSession session, ResolutionScope resolutionScope) {
168 return new ScopeDependencyFilter(null, getDirectlyExcludedLabels(translate(resolutionScope)));
169 }
170
171 @Override
172 public CollectResult postProcess(
173 RepositorySystemSession session, ResolutionScope resolutionScope, CollectResult collectResult) {
174 ResolutionScopeImpl rs = translate(resolutionScope);
175 if (rs.getMode() == Mode.ELIMINATE) {
176 CloningDependencyVisitor cloning = new CloningDependencyVisitor();
177 FilteringDependencyVisitor filter = new FilteringDependencyVisitor(
178 cloning, new ScopeDependencyFilter(null, getDirectlyExcludedLabels(rs)));
179 collectResult.getRoot().accept(filter);
180 collectResult.setRoot(cloning.getRootNode());
181 }
182 return collectResult;
183 }
184
185 @Override
186 public DependencyScope createDependencyScope(String id, boolean transitive, Collection<BuildScopeQuery> presence) {
187 return new DependencyScopeImpl(id, transitive, presence);
188 }
189
190 @Override
191 public SystemDependencyScope createSystemDependencyScope(
192 String id, boolean transitive, Collection<BuildScopeQuery> presence, String systemPathProperty) {
193 SystemDependencyScopeImpl system = new SystemDependencyScopeImpl(id, transitive, presence, systemPathProperty);
194 if (systemDependencyScope.compareAndSet(null, system)) {
195 return system;
196 } else {
197 throw new IllegalStateException("system dependency scope already created");
198 }
199 }
200
201 @Override
202 public ResolutionScope createResolutionScope(
203 String id,
204 Set<String> aliases,
205 Mode mode,
206 Collection<BuildScopeQuery> wantedPresence,
207 Collection<DependencyScope> explicitlyIncluded,
208 Collection<DependencyScope> transitivelyExcluded) {
209 return new ResolutionScopeImpl(id, aliases, mode, wantedPresence, explicitlyIncluded, transitivelyExcluded);
210 }
211
212 private Set<DependencyScope> collectScopes(Collection<BuildScopeQuery> wantedPresence) {
213 HashSet<DependencyScope> result = new HashSet<>();
214 for (BuildScope buildScope : buildScopeSource.query(wantedPresence)) {
215 dependencyScopes.values().stream()
216 .filter(s -> buildScopeSource.query(s.getPresence()).contains(buildScope))
217 .filter(s -> systemDependencyScope.get() == null
218 || !systemDependencyScope.get().is(s.id))
219 .forEach(result::add);
220 }
221 return result;
222 }
223
224 private int calculateDependencyScopeWidth(DependencyScopeImpl dependencyScope) {
225 int result = 0;
226 if (dependencyScope.isTransitive()) {
227 result += 1000;
228 }
229 for (BuildScope buildScope : buildScopeSource.query(dependencyScope.getPresence())) {
230 result += 1000
231 / buildScope.getProjectPaths().stream()
232 .map(ProjectPath::order)
233 .reduce(0, Integer::sum);
234 }
235 return result;
236 }
237
238 private BuildScope calculateMainProjectBuildScope(DependencyScopeImpl dependencyScope) {
239 for (ProjectPath projectPath : buildScopeSource.allProjectPaths().stream()
240 .sorted(Comparator.comparing(ProjectPath::order))
241 .collect(Collectors.toList())) {
242 for (BuildPath buildPath : buildScopeSource.allBuildPaths().stream()
243 .sorted(Comparator.comparing(BuildPath::order))
244 .collect(Collectors.toList())) {
245 for (BuildScope buildScope : buildScopeSource.query(dependencyScope.getPresence())) {
246 if (buildScope.getProjectPaths().contains(projectPath)
247 && buildScope.getBuildPaths().contains(buildPath)) {
248 return buildScope;
249 }
250 }
251 }
252 }
253 return null;
254 }
255
256
257
258
259 Set<String> getDirectlyIncludedLabels(ResolutionScope resolutionScope) {
260 return translate(resolutionScope).getDirectlyIncluded().stream()
261 .map(DependencyScope::getId)
262 .collect(Collectors.toSet());
263 }
264
265
266
267
268 Set<String> getDirectlyExcludedLabels(ResolutionScope resolutionScope) {
269 ResolutionScopeImpl rs = translate(resolutionScope);
270 return dependencyScopes.values().stream()
271 .filter(s -> !rs.getDirectlyIncluded().contains(s))
272 .map(DependencyScope::getId)
273 .collect(Collectors.toSet());
274 }
275
276
277
278
279 Set<String> getTransitivelyExcludedLabels(ResolutionScope resolutionScope) {
280 return translate(resolutionScope).getTransitivelyExcluded().stream()
281 .map(DependencyScope::getId)
282 .collect(Collectors.toSet());
283 }
284
285
286
287
288 Set<BuildScopeQuery> getPresence(DependencyScope dependencyScope) {
289 return translate(dependencyScope).getPresence();
290 }
291
292
293
294
295 BuildScopeSource getBuildScopeSource() {
296 return buildScopeSource;
297 }
298
299 private DependencyScopeImpl translate(DependencyScope dependencyScope) {
300 return requireNonNull(dependencyScopes.get(dependencyScope.getId()), "unknown dependency scope");
301 }
302
303 private ResolutionScopeImpl translate(ResolutionScope resolutionScope) {
304 return requireNonNull(resolutionScopes.get(resolutionScope.getId()), "unknown resolution scope");
305 }
306
307 @Override
308 public boolean equals(Object o) {
309 if (this == o) {
310 return true;
311 }
312 if (o == null || getClass() != o.getClass()) {
313 return false;
314 }
315 ScopeManagerImpl that = (ScopeManagerImpl) o;
316 return Objects.equals(id, that.id);
317 }
318
319 @Override
320 public int hashCode() {
321 return Objects.hash(id);
322 }
323
324 @Override
325 public String toString() {
326 return id;
327 }
328
329 private class DependencyScopeImpl implements DependencyScope {
330 private final String id;
331 private final boolean transitive;
332 private final Set<BuildScopeQuery> presence;
333 private final BuildScope mainBuildScope;
334 private final int width;
335
336 private DependencyScopeImpl(String id, boolean transitive, Collection<BuildScopeQuery> presence) {
337 this.id = requireNonNull(id, "id");
338 this.transitive = transitive;
339 this.presence = Collections.unmodifiableSet(new HashSet<>(presence));
340 this.mainBuildScope = calculateMainProjectBuildScope(this);
341 this.width = calculateDependencyScopeWidth(this);
342 }
343
344 @Override
345 public String getId() {
346 return id;
347 }
348
349 @Override
350 public boolean isTransitive() {
351 return transitive;
352 }
353
354 public Set<BuildScopeQuery> getPresence() {
355 return presence;
356 }
357
358 public BuildScope getMainBuildScope() {
359 return mainBuildScope;
360 }
361
362 public int getWidth() {
363 return width;
364 }
365
366 @Override
367 public boolean equals(Object o) {
368 if (this == o) {
369 return true;
370 }
371 if (o == null || getClass() != o.getClass()) {
372 return false;
373 }
374 DependencyScopeImpl that = (DependencyScopeImpl) o;
375 return Objects.equals(id, that.id);
376 }
377
378 @Override
379 public int hashCode() {
380 return Objects.hash(id);
381 }
382
383 @Override
384 public String toString() {
385 return id;
386 }
387 }
388
389 private class SystemDependencyScopeImpl extends DependencyScopeImpl implements SystemDependencyScope {
390 private final String systemPathProperty;
391
392 private SystemDependencyScopeImpl(
393 String id, boolean transitive, Collection<BuildScopeQuery> presence, String systemPathProperty) {
394 super(id, transitive, presence);
395 this.systemPathProperty = requireNonNull(systemPathProperty);
396 }
397
398 @Override
399 public String getSystemPath(Artifact artifact) {
400 return artifact.getProperty(systemPathProperty, null);
401 }
402
403 @Override
404 public void setSystemPath(Map<String, String> properties, String systemPath) {
405 if (systemPath == null) {
406 properties.remove(systemPathProperty);
407 } else {
408 properties.put(systemPathProperty, systemPath);
409 }
410 }
411 }
412
413 private class ResolutionScopeImpl implements ResolutionScope {
414 private final String id;
415 private final Set<String> aliases;
416 private final Mode mode;
417 private final Set<BuildScopeQuery> wantedPresence;
418 private final Set<DependencyScope> directlyIncluded;
419 private final Set<DependencyScope> transitivelyExcluded;
420
421 private ResolutionScopeImpl(
422 String id,
423 Set<String> aliases,
424 Mode mode,
425 Collection<BuildScopeQuery> wantedPresence,
426 Collection<DependencyScope> explicitlyIncluded,
427 Collection<DependencyScope> transitivelyExcluded) {
428 this.id = requireNonNull(id, "id");
429 this.aliases = Collections.unmodifiableSet(new HashSet<>(aliases));
430 this.mode = requireNonNull(mode, "mode");
431 this.wantedPresence = Collections.unmodifiableSet(new HashSet<>(wantedPresence));
432 Set<DependencyScope> included = collectScopes(wantedPresence);
433
434 if (explicitlyIncluded != null && !explicitlyIncluded.isEmpty()) {
435 explicitlyIncluded.stream().filter(Objects::nonNull).forEach(included::add);
436 }
437 this.directlyIncluded = Collections.unmodifiableSet(included);
438 this.transitivelyExcluded = Collections.unmodifiableSet(
439 transitivelyExcluded.stream().filter(Objects::nonNull).collect(Collectors.toSet()));
440 }
441
442 @Override
443 public String getId() {
444 return id;
445 }
446
447 @Override
448 public Set<String> getAliases() {
449 return aliases;
450 }
451
452 public Mode getMode() {
453 return mode;
454 }
455
456 public Set<BuildScopeQuery> getWantedPresence() {
457 return wantedPresence;
458 }
459
460 public Set<DependencyScope> getDirectlyIncluded() {
461 return directlyIncluded;
462 }
463
464 public Set<DependencyScope> getTransitivelyExcluded() {
465 return transitivelyExcluded;
466 }
467
468 @Override
469 public boolean equals(Object o) {
470 if (this == o) {
471 return true;
472 }
473 if (o == null || getClass() != o.getClass()) {
474 return false;
475 }
476 ResolutionScopeImpl that = (ResolutionScopeImpl) o;
477 return Objects.equals(id, that.id);
478 }
479
480 @Override
481 public int hashCode() {
482 return Objects.hash(id);
483 }
484
485 @Override
486 public String toString() {
487 return id;
488 }
489 }
490 }