View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.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.Set;
28  import java.util.concurrent.atomic.AtomicInteger;
29  import java.util.stream.Collectors;
30  import java.util.stream.Stream;
31  
32  import static java.util.Objects.requireNonNull;
33  
34  /**
35   * Generic matrix generator for {@link ProjectPath} and {@link BuildPath} combinations (all of them).
36   *
37   * @since 2.0.0
38   */
39  public final class BuildScopeMatrixSource implements BuildScopeSource {
40      private final Set<ProjectPath> projectPaths;
41      private final Set<BuildPath> buildPaths;
42      private final Map<String, BuildScope> buildScopes;
43  
44      public BuildScopeMatrixSource(
45              Collection<ProjectPath> projectPaths, Collection<BuildPath> buildPaths, BuildScope... extras) {
46          requireNonNull(projectPaths, "projectPath");
47          requireNonNull(buildPaths, "buildPaths");
48          if (projectPaths.isEmpty() || buildPaths.isEmpty()) {
49              throw new IllegalArgumentException("empty matrix");
50          }
51          HashMap<String, BuildScope> buildScopes = new HashMap<>();
52          AtomicInteger counter = new AtomicInteger(0);
53          buildPaths.stream().sorted(Comparator.comparing(BuildPath::order)).forEach(buildPath -> {
54              Stream<ProjectPath> projectPathStream;
55              if (buildPath.isReverse()) {
56                  projectPathStream = projectPaths.stream().sorted(Comparator.comparing(ProjectPath::reverseOrder));
57              } else {
58                  projectPathStream = projectPaths.stream().sorted(Comparator.comparing(ProjectPath::order));
59              }
60              projectPathStream.forEach(projectPath -> {
61                  String id = createId(projectPath, buildPath);
62                  buildScopes.put(
63                          id,
64                          new BuildScopeImpl(
65                                  id,
66                                  Collections.singleton(projectPath),
67                                  Collections.singleton(buildPath),
68                                  counter.incrementAndGet()));
69              });
70          });
71          for (BuildScope extra : extras) {
72              buildScopes.put(extra.getId(), extra);
73          }
74          this.buildScopes = Collections.unmodifiableMap(buildScopes);
75  
76          // now collect all paths
77          HashSet<ProjectPath> pp = new HashSet<>(projectPaths);
78          HashSet<BuildPath> bp = new HashSet<>(buildPaths);
79          buildScopes.values().forEach(s -> {
80              pp.addAll(s.getProjectPaths());
81              bp.addAll(s.getBuildPaths());
82          });
83          this.projectPaths = Collections.unmodifiableSet(pp);
84          this.buildPaths = Collections.unmodifiableSet(bp);
85      }
86  
87      private String createId(ProjectPath projectPath, BuildPath buildPath) {
88          return projectPath.getId() + "-" + buildPath.getId();
89      }
90  
91      @Override
92      public Collection<BuildScope> query(Collection<BuildScopeQuery> queries) {
93          HashSet<BuildScope> result = new HashSet<>();
94          for (BuildScopeQuery query : queries) {
95              switch (query.getMode()) {
96                  case ALL:
97                      result.addAll(all());
98                      break; // we added all, whatever is after this, is unimportant
99                  case BY_PROJECT_PATH:
100                     result.addAll(byProjectPath(query.getProjectPath()));
101                     continue;
102                 case BY_BUILD_PATH:
103                     result.addAll(byBuildPath(query.getBuildPath()));
104                     continue;
105                 case SELECT:
106                     result.addAll(select(query.getProjectPath(), query.getBuildPath()));
107                     continue;
108                 case SINGLETON:
109                     result.addAll(singleton(query.getProjectPath(), query.getBuildPath()));
110                     continue;
111                 default:
112                     throw new IllegalArgumentException("Unsupported query");
113             }
114         }
115         return result;
116     }
117 
118     @Override
119     public Collection<ProjectPath> allProjectPaths() {
120         return projectPaths;
121     }
122 
123     @Override
124     public Collection<BuildPath> allBuildPaths() {
125         return buildPaths;
126     }
127 
128     private Collection<BuildScope> all() {
129         return buildScopes.values();
130     }
131 
132     private Collection<BuildScope> byProjectPath(ProjectPath projectPath) {
133         return all().stream()
134                 .filter(s -> s.getProjectPaths().contains(projectPath))
135                 .collect(Collectors.toSet());
136     }
137 
138     private Collection<BuildScope> byBuildPath(BuildPath buildPath) {
139         return all().stream().filter(s -> s.getBuildPaths().contains(buildPath)).collect(Collectors.toSet());
140     }
141 
142     private Collection<BuildScope> singleton(ProjectPath projectPath, BuildPath buildPath) {
143         BuildScope result = buildScopes.get(createId(projectPath, buildPath));
144         if (result == null) {
145             throw new IllegalArgumentException("no such build scope");
146         }
147         return Collections.singleton(result);
148     }
149 
150     private Collection<BuildScope> select(ProjectPath projectPath, BuildPath buildPath) {
151         HashSet<BuildScope> result = new HashSet<>();
152         buildScopes.values().stream()
153                 .filter(s -> s.getProjectPaths().contains(projectPath)
154                         && s.getBuildPaths().contains(buildPath))
155                 .forEach(result::add);
156         return result;
157     }
158 
159     private static final class BuildScopeImpl implements BuildScope {
160         private final String id;
161         private final Set<ProjectPath> projectPaths;
162         private final Set<BuildPath> buildPaths;
163         private final int order;
164 
165         private BuildScopeImpl(String id, Set<ProjectPath> projectPaths, Set<BuildPath> buildPaths, int order) {
166             this.id = id;
167             this.projectPaths = projectPaths;
168             this.buildPaths = buildPaths;
169             this.order = order;
170         }
171 
172         @Override
173         public String getId() {
174             return id;
175         }
176 
177         @Override
178         public Set<ProjectPath> getProjectPaths() {
179             return projectPaths;
180         }
181 
182         @Override
183         public Set<BuildPath> getBuildPaths() {
184             return buildPaths;
185         }
186 
187         @Override
188         public int order() {
189             return order;
190         }
191     }
192 }