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