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