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 Map<String, ResolutionScopeImpl> resolutionScopes;
68
69 public ScopeManagerImpl(ScopeManagerConfiguration configuration) {
70 this.id = configuration.getId();
71 this.strictDependencyScopes = configuration.isStrictDependencyScopes();
72 this.strictResolutionScopes = configuration.isStrictResolutionScopes();
73 this.buildScopeSource = configuration.getBuildScopeSource();
74 this.systemDependencyScope = new AtomicReference<>(null);
75 this.dependencyScopes = Collections.unmodifiableMap(buildDependencyScopes(configuration));
76 this.resolutionScopes = Collections.unmodifiableMap(buildResolutionScopes(configuration));
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 new HashSet<>(dependencyScopes.values());
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 new HashSet<>(resolutionScopes.values());
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(ResolutionScope resolutionScope) {
143 ResolutionScopeImpl rs = translate(resolutionScope);
144 Set<String> directlyExcludedLabels = getDirectlyExcludedLabels(rs);
145 Set<String> transitivelyExcludedLabels = getTransitivelyExcludedLabels(rs);
146
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 }
155
156 @Override
157 public DependencyGraphTransformer getDependencyGraphTransformer(ResolutionScope resolutionScope) {
158 return new ChainedDependencyGraphTransformer(
159 new ConflictResolver(
160 new ConfigurableVersionSelector(), new ManagedScopeSelector(this),
161 new SimpleOptionalitySelector(), new ManagedScopeDeriver(this)),
162 new ManagedDependencyContextRefiner(this));
163 }
164
165 @Override
166 public CollectResult postProcess(ResolutionScope resolutionScope, CollectResult collectResult) {
167 ResolutionScopeImpl rs = translate(resolutionScope);
168 if (rs.getMode() == Mode.ELIMINATE) {
169 CloningDependencyVisitor cloning = new CloningDependencyVisitor();
170 FilteringDependencyVisitor filter = new FilteringDependencyVisitor(
171 cloning, new ScopeDependencyFilter(null, getDirectlyExcludedLabels(rs)));
172 collectResult.getRoot().accept(filter);
173 collectResult.setRoot(cloning.getRootNode());
174 }
175 return collectResult;
176 }
177
178 @Override
179 public DependencyFilter getDependencyFilter(ResolutionScope resolutionScope) {
180 return new ScopeDependencyFilter(null, getDirectlyExcludedLabels(translate(resolutionScope)));
181 }
182
183 @Override
184 public DependencyScope createDependencyScope(String id, boolean transitive, Collection<BuildScopeQuery> presence) {
185 return new DependencyScopeImpl(id, transitive, presence);
186 }
187
188 @Override
189 public SystemDependencyScope createSystemDependencyScope(
190 String id, boolean transitive, Collection<BuildScopeQuery> presence, String systemPathProperty) {
191 SystemDependencyScopeImpl system = new SystemDependencyScopeImpl(id, transitive, presence, systemPathProperty);
192 if (systemDependencyScope.compareAndSet(null, system)) {
193 return system;
194 } else {
195 throw new IllegalStateException("system dependency scope already created");
196 }
197 }
198
199 @Override
200 public ResolutionScope createResolutionScope(
201 String id,
202 Mode mode,
203 Collection<BuildScopeQuery> wantedPresence,
204 Collection<DependencyScope> explicitlyIncluded,
205 Collection<DependencyScope> transitivelyExcluded) {
206 return new ResolutionScopeImpl(id, mode, wantedPresence, explicitlyIncluded, transitivelyExcluded);
207 }
208
209 private Set<DependencyScope> collectScopes(Collection<BuildScopeQuery> wantedPresence) {
210 HashSet<DependencyScope> result = new HashSet<>();
211 for (BuildScope buildScope : buildScopeSource.query(wantedPresence)) {
212 dependencyScopes.values().stream()
213 .filter(s -> buildScopeSource.query(s.getPresence()).contains(buildScope))
214 .filter(s -> systemDependencyScope.get() == null
215 || !systemDependencyScope.get().is(s.id))
216 .forEach(result::add);
217 }
218 return result;
219 }
220
221 private int calculateDependencyScopeWidth(DependencyScopeImpl dependencyScope) {
222 int result = 0;
223 if (dependencyScope.isTransitive()) {
224 result += 1000;
225 }
226 for (BuildScope buildScope : buildScopeSource.query(dependencyScope.getPresence())) {
227 result += 1000
228 / buildScope.getProjectPaths().stream()
229 .map(ProjectPath::order)
230 .reduce(0, Integer::sum);
231 }
232 return result;
233 }
234
235 private BuildScope calculateMainProjectBuildScope(DependencyScopeImpl dependencyScope) {
236 for (ProjectPath projectPath : buildScopeSource.allProjectPaths().stream()
237 .sorted(Comparator.comparing(ProjectPath::order))
238 .collect(Collectors.toList())) {
239 for (BuildPath buildPath : buildScopeSource.allBuildPaths().stream()
240 .sorted(Comparator.comparing(BuildPath::order))
241 .collect(Collectors.toList())) {
242 for (BuildScope buildScope : buildScopeSource.query(dependencyScope.getPresence())) {
243 if (buildScope.getProjectPaths().contains(projectPath)
244 && buildScope.getBuildPaths().contains(buildPath)) {
245 return buildScope;
246 }
247 }
248 }
249 }
250 return null;
251 }
252
253
254
255
256 Set<String> getDirectlyIncludedLabels(ResolutionScope resolutionScope) {
257 return translate(resolutionScope).getDirectlyIncluded().stream()
258 .map(DependencyScope::getId)
259 .collect(Collectors.toSet());
260 }
261
262
263
264
265 Set<String> getDirectlyExcludedLabels(ResolutionScope resolutionScope) {
266 ResolutionScopeImpl rs = translate(resolutionScope);
267 return dependencyScopes.values().stream()
268 .filter(s -> !rs.getDirectlyIncluded().contains(s))
269 .map(DependencyScope::getId)
270 .collect(Collectors.toSet());
271 }
272
273
274
275
276 Set<String> getTransitivelyExcludedLabels(ResolutionScope resolutionScope) {
277 return translate(resolutionScope).getTransitivelyExcluded().stream()
278 .map(DependencyScope::getId)
279 .collect(Collectors.toSet());
280 }
281
282
283
284
285 Set<BuildScopeQuery> getPresence(DependencyScope dependencyScope) {
286 return translate(dependencyScope).getPresence();
287 }
288
289
290
291
292 BuildScopeSource getBuildScopeSource() {
293 return buildScopeSource;
294 }
295
296 private DependencyScopeImpl translate(DependencyScope dependencyScope) {
297 return requireNonNull(dependencyScopes.get(dependencyScope.getId()), "unknown dependency scope");
298 }
299
300 private ResolutionScopeImpl translate(ResolutionScope resolutionScope) {
301 return requireNonNull(resolutionScopes.get(resolutionScope.getId()), "unknown resolution scope");
302 }
303
304 @Override
305 public boolean equals(Object o) {
306 if (this == o) {
307 return true;
308 }
309 if (o == null || getClass() != o.getClass()) {
310 return false;
311 }
312 ScopeManagerImpl that = (ScopeManagerImpl) o;
313 return Objects.equals(id, that.id);
314 }
315
316 @Override
317 public int hashCode() {
318 return Objects.hash(id);
319 }
320
321 @Override
322 public String toString() {
323 return id;
324 }
325
326 private class DependencyScopeImpl implements DependencyScope {
327 private final String id;
328 private final boolean transitive;
329 private final Set<BuildScopeQuery> presence;
330 private final BuildScope mainBuildScope;
331 private final int width;
332
333 private DependencyScopeImpl(String id, boolean transitive, Collection<BuildScopeQuery> presence) {
334 this.id = requireNonNull(id, "id");
335 this.transitive = transitive;
336 this.presence = Collections.unmodifiableSet(new HashSet<>(presence));
337 this.mainBuildScope = calculateMainProjectBuildScope(this);
338 this.width = calculateDependencyScopeWidth(this);
339 }
340
341 @Override
342 public String getId() {
343 return id;
344 }
345
346 @Override
347 public boolean isTransitive() {
348 return transitive;
349 }
350
351 public Set<BuildScopeQuery> getPresence() {
352 return presence;
353 }
354
355 public BuildScope getMainBuildScope() {
356 return mainBuildScope;
357 }
358
359 public int getWidth() {
360 return width;
361 }
362
363 @Override
364 public boolean equals(Object o) {
365 if (this == o) {
366 return true;
367 }
368 if (o == null || getClass() != o.getClass()) {
369 return false;
370 }
371 DependencyScopeImpl that = (DependencyScopeImpl) o;
372 return Objects.equals(id, that.id);
373 }
374
375 @Override
376 public int hashCode() {
377 return Objects.hash(id);
378 }
379
380 @Override
381 public String toString() {
382 return id;
383 }
384 }
385
386 private class SystemDependencyScopeImpl extends DependencyScopeImpl implements SystemDependencyScope {
387 private final String systemPathProperty;
388
389 private SystemDependencyScopeImpl(
390 String id, boolean transitive, Collection<BuildScopeQuery> presence, String systemPathProperty) {
391 super(id, transitive, presence);
392 this.systemPathProperty = requireNonNull(systemPathProperty);
393 }
394
395 @Override
396 public String getSystemPath(Artifact artifact) {
397 return artifact.getProperty(systemPathProperty, null);
398 }
399
400 @Override
401 public void setSystemPath(Map<String, String> properties, String systemPath) {
402 if (systemPath == null) {
403 properties.remove(systemPathProperty);
404 } else {
405 properties.put(systemPathProperty, systemPath);
406 }
407 }
408 }
409
410 private class ResolutionScopeImpl implements ResolutionScope {
411
412 private final String id;
413 private final Mode mode;
414 private final Set<BuildScopeQuery> wantedPresence;
415 private final Set<DependencyScope> directlyIncluded;
416 private final Set<DependencyScope> transitivelyExcluded;
417
418 private ResolutionScopeImpl(
419 String id,
420 Mode mode,
421 Collection<BuildScopeQuery> wantedPresence,
422 Collection<DependencyScope> explicitlyIncluded,
423 Collection<DependencyScope> transitivelyExcluded) {
424 this.id = requireNonNull(id, "id");
425 this.mode = requireNonNull(mode, "mode");
426 this.wantedPresence = Collections.unmodifiableSet(new HashSet<>(wantedPresence));
427 Set<DependencyScope> included = collectScopes(wantedPresence);
428
429 if (explicitlyIncluded != null && !explicitlyIncluded.isEmpty()) {
430 explicitlyIncluded.stream().filter(Objects::nonNull).forEach(included::add);
431 }
432 this.directlyIncluded = Collections.unmodifiableSet(included);
433 this.transitivelyExcluded = Collections.unmodifiableSet(
434 transitivelyExcluded.stream().filter(Objects::nonNull).collect(Collectors.toSet()));
435 }
436
437 @Override
438 public String getId() {
439 return id;
440 }
441
442 public Mode getMode() {
443 return mode;
444 }
445
446 public Set<BuildScopeQuery> getWantedPresence() {
447 return wantedPresence;
448 }
449
450 public Set<DependencyScope> getDirectlyIncluded() {
451 return directlyIncluded;
452 }
453
454 public Set<DependencyScope> getTransitivelyExcluded() {
455 return transitivelyExcluded;
456 }
457
458 @Override
459 public boolean equals(Object o) {
460 if (this == o) {
461 return true;
462 }
463 if (o == null || getClass() != o.getClass()) {
464 return false;
465 }
466 ResolutionScopeImpl that = (ResolutionScopeImpl) o;
467 return Objects.equals(id, that.id);
468 }
469
470 @Override
471 public int hashCode() {
472 return Objects.hash(id);
473 }
474
475 @Override
476 public String toString() {
477 return id;
478 }
479 }
480 }