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.apache.maven.project.artifact;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.LinkedHashSet;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Objects;
32  import java.util.Set;
33  import java.util.concurrent.ConcurrentHashMap;
34  
35  import org.apache.maven.RepositoryUtils;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.lifecycle.LifecycleExecutionException;
38  import org.apache.maven.lifecycle.internal.SetWithResolutionResult;
39  import org.apache.maven.project.MavenProject;
40  import org.eclipse.aether.RepositorySystemSession;
41  import org.eclipse.aether.repository.LocalRepository;
42  import org.eclipse.aether.repository.RemoteRepository;
43  import org.eclipse.aether.repository.WorkspaceRepository;
44  
45  /**
46   */
47  @Named
48  @Singleton
49  public class DefaultProjectArtifactsCache implements ProjectArtifactsCache {
50      /**
51       * CacheKey
52       */
53      protected static class CacheKey implements Key {
54  
55          private final String groupId;
56  
57          private final String artifactId;
58  
59          private final String version;
60  
61          private final Set<String> dependencyArtifacts;
62  
63          private final WorkspaceRepository workspace;
64  
65          private final LocalRepository localRepo;
66  
67          private final List<RemoteRepository> repositories;
68  
69          private final Set<String> collect;
70  
71          private final Set<String> resolve;
72  
73          private boolean aggregating;
74  
75          private final int hashCode;
76  
77          public CacheKey(
78                  MavenProject project,
79                  List<RemoteRepository> repositories,
80                  Collection<String> scopesToCollect,
81                  Collection<String> scopesToResolve,
82                  boolean aggregating,
83                  RepositorySystemSession session) {
84  
85              groupId = project.getGroupId();
86              artifactId = project.getArtifactId();
87              version = project.getVersion();
88  
89              Set<String> deps = new LinkedHashSet<>();
90              if (project.getDependencyArtifacts() != null) {
91                  for (Artifact dep : project.getDependencyArtifacts()) {
92                      deps.add(dep.toString());
93                  }
94              }
95              dependencyArtifacts = Collections.unmodifiableSet(deps);
96  
97              workspace = RepositoryUtils.getWorkspace(session);
98              this.localRepo = session.getLocalRepository();
99              this.repositories = new ArrayList<>(repositories.size());
100             for (RemoteRepository repository : repositories) {
101                 if (repository.isRepositoryManager()) {
102                     this.repositories.addAll(repository.getMirroredRepositories());
103                 } else {
104                     this.repositories.add(repository);
105                 }
106             }
107             collect = scopesToCollect == null
108                     ? Collections.emptySet()
109                     : Collections.unmodifiableSet(new HashSet<>(scopesToCollect));
110             resolve = scopesToResolve == null
111                     ? Collections.emptySet()
112                     : Collections.unmodifiableSet(new HashSet<>(scopesToResolve));
113             this.aggregating = aggregating;
114 
115             int hash = 17;
116             hash = hash * 31 + Objects.hashCode(groupId);
117             hash = hash * 31 + Objects.hashCode(artifactId);
118             hash = hash * 31 + Objects.hashCode(version);
119             hash = hash * 31 + Objects.hashCode(dependencyArtifacts);
120             hash = hash * 31 + Objects.hashCode(workspace);
121             hash = hash * 31 + Objects.hashCode(localRepo);
122             hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
123             hash = hash * 31 + Objects.hashCode(collect);
124             hash = hash * 31 + Objects.hashCode(resolve);
125             hash = hash * 31 + Objects.hashCode(aggregating);
126             this.hashCode = hash;
127         }
128 
129         @Override
130         public String toString() {
131             return groupId + ":" + artifactId + ":" + version;
132         }
133 
134         @Override
135         public int hashCode() {
136             return hashCode;
137         }
138 
139         @Override
140         public boolean equals(Object o) {
141             if (o == this) {
142                 return true;
143             }
144             if (!(o instanceof CacheKey)) {
145                 return false;
146             }
147             CacheKey that = (CacheKey) o;
148             return Objects.equals(groupId, that.groupId)
149                     && Objects.equals(artifactId, that.artifactId)
150                     && Objects.equals(version, that.version)
151                     && Objects.equals(dependencyArtifacts, that.dependencyArtifacts)
152                     && Objects.equals(workspace, that.workspace)
153                     && Objects.equals(localRepo, that.localRepo)
154                     && RepositoryUtils.repositoriesEquals(repositories, that.repositories)
155                     && Objects.equals(collect, that.collect)
156                     && Objects.equals(resolve, that.resolve)
157                     && aggregating == that.aggregating;
158         }
159     }
160 
161     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
162     protected final Map<Key, Key> keys = new ConcurrentHashMap<>();
163 
164     @Override
165     public Key createKey(
166             MavenProject project,
167             Collection<String> scopesToCollect,
168             Collection<String> scopesToResolve,
169             boolean aggregating,
170             RepositorySystemSession session) {
171         Key key = new CacheKey(
172                 project,
173                 project.getRemoteProjectRepositories(),
174                 scopesToCollect,
175                 scopesToResolve,
176                 aggregating,
177                 session);
178         return keys.computeIfAbsent(key, k -> k);
179     }
180 
181     @Override
182     public CacheRecord get(Key key) throws LifecycleExecutionException {
183         CacheRecord cacheRecord = cache.get(key);
184         if (cacheRecord != null && cacheRecord.getException() != null) {
185             throw cacheRecord.getException();
186         }
187         return cacheRecord;
188     }
189 
190     @Override
191     public CacheRecord put(Key key, Set<Artifact> projectArtifacts) {
192         Objects.requireNonNull(projectArtifacts, "projectArtifacts cannot be null");
193         assertUniqueKey(key);
194 
195         SetWithResolutionResult artifacts;
196         if (projectArtifacts instanceof SetWithResolutionResult) {
197             artifacts = (SetWithResolutionResult) projectArtifacts;
198         } else if (projectArtifacts instanceof ArtifactsSetWithResult) {
199             artifacts = new SetWithResolutionResult(
200                     ((ArtifactsSetWithResult) projectArtifacts).getResult(), projectArtifacts);
201         } else {
202             throw new IllegalArgumentException("projectArtifacts must implement ArtifactsSetWithResult");
203         }
204 
205         CacheRecord record = new CacheRecord(artifacts);
206         cache.put(key, record);
207         return record;
208     }
209 
210     @Override
211     public CacheRecord put(Key key, LifecycleExecutionException exception) {
212         Objects.requireNonNull(exception, "exception cannot be null");
213         assertUniqueKey(key);
214         CacheRecord record = new CacheRecord(exception);
215         cache.put(key, record);
216         return record;
217     }
218 
219     protected void assertUniqueKey(Key key) {
220         if (cache.containsKey(key)) {
221             throw new IllegalStateException("Duplicate artifact resolution result for project " + key);
222         }
223     }
224 
225     @Override
226     public void flush() {
227         cache.clear();
228     }
229 
230     @Override
231     public void register(MavenProject project, Key cacheKey, CacheRecord record) {
232         // default cache does not track record usage
233     }
234 }