1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project.artifact;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap;
31 import javax.inject.Named;
32 import javax.inject.Singleton;
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.ArtifactUtils;
35 import org.apache.maven.artifact.metadata.ResolutionGroup;
36 import org.apache.maven.artifact.repository.ArtifactRepository;
37 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
38
39
40
41
42 @Named
43 @Singleton
44 public class DefaultMavenMetadataCache implements MavenMetadataCache {
45
46 protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<>();
47
48
49
50
51 public static class CacheKey {
52 private final Artifact artifact;
53 private final long pomHash;
54 private final boolean resolveManagedVersions;
55 private final List<ArtifactRepository> repositories = new ArrayList<>();
56 private final int hashCode;
57
58 public CacheKey(
59 Artifact artifact,
60 boolean resolveManagedVersions,
61 ArtifactRepository localRepository,
62 List<ArtifactRepository> remoteRepositories) {
63 File file = artifact.getFile();
64 this.artifact = ArtifactUtils.copyArtifact(artifact);
65 if ("pom".equals(artifact.getType()) && file != null) {
66 pomHash = file.getPath().hashCode() + file.lastModified();
67 } else {
68 pomHash = 0;
69 }
70 this.resolveManagedVersions = resolveManagedVersions;
71 this.repositories.add(localRepository);
72 this.repositories.addAll(remoteRepositories);
73
74 int hash = 17;
75 hash = hash * 31 + artifactHashCode(artifact);
76 hash = hash * 31 + (resolveManagedVersions ? 1 : 2);
77 hash = hash * 31 + repositoriesHashCode(repositories);
78 this.hashCode = hash;
79 }
80
81 @Override
82 public int hashCode() {
83 return hashCode;
84 }
85
86 @Override
87 public boolean equals(Object o) {
88 if (o == this) {
89 return true;
90 }
91
92 if (!(o instanceof CacheKey)) {
93 return false;
94 }
95
96 CacheKey other = (CacheKey) o;
97
98 return pomHash == other.pomHash
99 && artifactEquals(artifact, other.artifact)
100 && resolveManagedVersions == other.resolveManagedVersions
101 && repositoriesEquals(repositories, other.repositories);
102 }
103 }
104
105 private static int artifactHashCode(Artifact a) {
106 int result = 17;
107 result = 31 * result + a.getGroupId().hashCode();
108 result = 31 * result + a.getArtifactId().hashCode();
109 result = 31 * result + a.getType().hashCode();
110 if (a.getVersion() != null) {
111 result = 31 * result + a.getVersion().hashCode();
112 }
113 result = 31 * result + (a.getClassifier() != null ? a.getClassifier().hashCode() : 0);
114 result = 31 * result + (a.getScope() != null ? a.getScope().hashCode() : 0);
115 result = 31 * result
116 + (a.getDependencyFilter() != null ? a.getDependencyFilter().hashCode() : 0);
117 result = 31 * result + (a.isOptional() ? 1 : 0);
118 return result;
119 }
120
121 private static boolean artifactEquals(Artifact a1, Artifact a2) {
122 if (a1 == a2) {
123 return true;
124 }
125
126 return Objects.equals(a1.getGroupId(), a2.getGroupId())
127 && Objects.equals(a1.getArtifactId(), a2.getArtifactId())
128 && Objects.equals(a1.getType(), a2.getType())
129 && Objects.equals(a1.getVersion(), a2.getVersion())
130 && Objects.equals(a1.getClassifier(), a2.getClassifier())
131 && Objects.equals(a1.getScope(), a2.getScope())
132 && Objects.equals(a1.getDependencyFilter(), a2.getDependencyFilter())
133 && a1.isOptional() == a2.isOptional();
134 }
135
136 private static int repositoryHashCode(ArtifactRepository repository) {
137 int result = 17;
138 result = 31 * result + (repository.getId() != null ? repository.getId().hashCode() : 0);
139 return result;
140 }
141
142 private static int repositoriesHashCode(List<ArtifactRepository> repositories) {
143 int result = 17;
144 for (ArtifactRepository repository : repositories) {
145 result = 31 * result + repositoryHashCode(repository);
146 }
147 return result;
148 }
149
150 private static boolean repositoryEquals(ArtifactRepository r1, ArtifactRepository r2) {
151 if (r1 == r2) {
152 return true;
153 }
154
155 return Objects.equals(r1.getId(), r2.getId())
156 && Objects.equals(r1.getUrl(), r2.getUrl())
157 && repositoryPolicyEquals(r1.getReleases(), r2.getReleases())
158 && repositoryPolicyEquals(r1.getSnapshots(), r2.getSnapshots());
159 }
160
161 private static boolean repositoryPolicyEquals(ArtifactRepositoryPolicy p1, ArtifactRepositoryPolicy p2) {
162 if (p1 == p2) {
163 return true;
164 }
165
166 return p1.isEnabled() == p2.isEnabled() && Objects.equals(p1.getUpdatePolicy(), p2.getUpdatePolicy());
167 }
168
169 private static boolean repositoriesEquals(List<ArtifactRepository> r1, List<ArtifactRepository> r2) {
170 if (r1.size() != r2.size()) {
171 return false;
172 }
173
174 for (Iterator<ArtifactRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); ) {
175 if (!repositoryEquals(it1.next(), it2.next())) {
176 return false;
177 }
178 }
179
180 return true;
181 }
182
183
184
185
186 public class CacheRecord {
187 private Artifact pomArtifact;
188 private Artifact relocatedArtifact;
189 private List<Artifact> artifacts;
190 private Map<String, Artifact> managedVersions;
191 private List<ArtifactRepository> remoteRepositories;
192
193 private long length;
194 private long timestamp;
195
196 CacheRecord(
197 Artifact pomArtifact,
198 Artifact relocatedArtifact,
199 Set<Artifact> artifacts,
200 Map<String, Artifact> managedVersions,
201 List<ArtifactRepository> remoteRepositories) {
202 this.pomArtifact = ArtifactUtils.copyArtifact(pomArtifact);
203 this.relocatedArtifact = ArtifactUtils.copyArtifactSafe(relocatedArtifact);
204 this.artifacts = ArtifactUtils.copyArtifacts(artifacts, new ArrayList<>());
205 this.remoteRepositories = new ArrayList<>(remoteRepositories);
206
207 this.managedVersions = managedVersions;
208 if (managedVersions != null) {
209 this.managedVersions = ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<>());
210 }
211
212 File pomFile = pomArtifact.getFile();
213 if (pomFile != null && pomFile.canRead()) {
214 this.length = pomFile.length();
215 this.timestamp = pomFile.lastModified();
216 } else {
217 this.length = -1;
218 this.timestamp = -1;
219 }
220 }
221
222 public Artifact getArtifact() {
223 return pomArtifact;
224 }
225
226 public Artifact getRelocatedArtifact() {
227 return relocatedArtifact;
228 }
229
230 public List<Artifact> getArtifacts() {
231 return artifacts;
232 }
233
234 public Map<String, Artifact> getManagedVersions() {
235 return managedVersions;
236 }
237
238 public List<ArtifactRepository> getRemoteRepositories() {
239 return remoteRepositories;
240 }
241
242 public boolean isStale() {
243 File pomFile = pomArtifact.getFile();
244 if (pomFile != null) {
245 if (pomFile.canRead()) {
246 return length != pomFile.length() || timestamp != pomFile.lastModified();
247 } else {
248
249 boolean snapshot = pomArtifact.isSnapshot();
250 for (ArtifactRepository repository : remoteRepositories) {
251 ArtifactRepositoryPolicy policy =
252 snapshot ? repository.getSnapshots() : repository.getReleases();
253 if (ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals(policy.getUpdatePolicy())) {
254 return true;
255 }
256 }
257 }
258 }
259
260 return length != -1 || timestamp != -1;
261 }
262 }
263
264 public ResolutionGroup get(
265 Artifact artifact,
266 boolean resolveManagedVersions,
267 ArtifactRepository localRepository,
268 List<ArtifactRepository> remoteRepositories) {
269 CacheKey cacheKey = newCacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories);
270
271 CacheRecord cacheRecord = cache.get(cacheKey);
272
273 if (cacheRecord != null && !cacheRecord.isStale()) {
274 Artifact pomArtifact = ArtifactUtils.copyArtifact(cacheRecord.getArtifact());
275 Artifact relocatedArtifact = ArtifactUtils.copyArtifactSafe(cacheRecord.getRelocatedArtifact());
276 Set<Artifact> artifacts = ArtifactUtils.copyArtifacts(cacheRecord.getArtifacts(), new LinkedHashSet<>());
277 Map<String, Artifact> managedVersions = cacheRecord.getManagedVersions();
278 if (managedVersions != null) {
279 managedVersions = ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<>());
280 }
281 return new ResolutionGroup(
282 pomArtifact, relocatedArtifact, artifacts, managedVersions, cacheRecord.getRemoteRepositories());
283 }
284
285 cache.remove(cacheKey);
286
287 return null;
288 }
289
290 public void put(
291 Artifact artifact,
292 boolean resolveManagedVersions,
293 ArtifactRepository localRepository,
294 List<ArtifactRepository> remoteRepositories,
295 ResolutionGroup result) {
296 put(newCacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories), result);
297 }
298
299 protected CacheKey newCacheKey(
300 Artifact artifact,
301 boolean resolveManagedVersions,
302 ArtifactRepository localRepository,
303 List<ArtifactRepository> remoteRepositories) {
304 return new CacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories);
305 }
306
307 protected void put(CacheKey cacheKey, ResolutionGroup result) {
308 CacheRecord cacheRecord = new CacheRecord(
309 result.getPomArtifact(),
310 result.getRelocatedArtifact(),
311 result.getArtifacts(),
312 result.getManagedVersions(),
313 result.getResolutionRepositories());
314
315 cache.put(cacheKey, cacheRecord);
316 }
317
318 public void flush() {
319 cache.clear();
320 }
321 }