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