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