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
32 import org.apache.maven.artifact.Artifact;
33 import org.apache.maven.artifact.ArtifactUtils;
34 import org.apache.maven.artifact.metadata.ResolutionGroup;
35 import org.apache.maven.artifact.repository.ArtifactRepository;
36 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
37 import org.codehaus.plexus.component.annotations.Component;
38
39
40
41
42 @Component(role = MavenMetadataCache.class)
43 public class DefaultMavenMetadataCache implements MavenMetadataCache {
44
45 protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<>();
46
47
48
49
50 public static class CacheKey {
51 private final Artifact artifact;
52 private final long pomHash;
53 private final boolean resolveManagedVersions;
54 private final List<ArtifactRepository> repositories = new ArrayList<>();
55 private final int hashCode;
56
57 public CacheKey(
58 Artifact artifact,
59 boolean resolveManagedVersions,
60 ArtifactRepository localRepository,
61 List<ArtifactRepository> remoteRepositories) {
62 File file = artifact.getFile();
63 this.artifact = ArtifactUtils.copyArtifact(artifact);
64 if ("pom".equals(artifact.getType()) && file != null) {
65 pomHash = file.getPath().hashCode() + file.lastModified();
66 } else {
67 pomHash = 0;
68 }
69 this.resolveManagedVersions = resolveManagedVersions;
70 this.repositories.add(localRepository);
71 this.repositories.addAll(remoteRepositories);
72
73 int hash = 17;
74 hash = hash * 31 + artifactHashCode(artifact);
75 hash = hash * 31 + (resolveManagedVersions ? 1 : 2);
76 hash = hash * 31 + repositoriesHashCode(repositories);
77 this.hashCode = hash;
78 }
79
80 @Override
81 public int hashCode() {
82 return hashCode;
83 }
84
85 @Override
86 public boolean equals(Object o) {
87 if (o == this) {
88 return true;
89 }
90
91 if (!(o instanceof CacheKey)) {
92 return false;
93 }
94
95 CacheKey other = (CacheKey) o;
96
97 return pomHash == other.pomHash
98 && artifactEquals(artifact, other.artifact)
99 && resolveManagedVersions == other.resolveManagedVersions
100 && repositoriesEquals(repositories, other.repositories);
101 }
102 }
103
104 private static int artifactHashCode(Artifact a) {
105 int result = 17;
106 result = 31 * result + a.getGroupId().hashCode();
107 result = 31 * result + a.getArtifactId().hashCode();
108 result = 31 * result + a.getType().hashCode();
109 if (a.getVersion() != null) {
110 result = 31 * result + a.getVersion().hashCode();
111 }
112 result = 31 * result + (a.getClassifier() != null ? a.getClassifier().hashCode() : 0);
113 result = 31 * result + (a.getScope() != null ? a.getScope().hashCode() : 0);
114 result = 31 * result
115 + (a.getDependencyFilter() != null ? a.getDependencyFilter().hashCode() : 0);
116 result = 31 * result + (a.isOptional() ? 1 : 0);
117 return result;
118 }
119
120 private static boolean artifactEquals(Artifact a1, Artifact a2) {
121 if (a1 == a2) {
122 return true;
123 }
124
125 return Objects.equals(a1.getGroupId(), a2.getGroupId())
126 && Objects.equals(a1.getArtifactId(), a2.getArtifactId())
127 && Objects.equals(a1.getType(), a2.getType())
128 && Objects.equals(a1.getVersion(), a2.getVersion())
129 && Objects.equals(a1.getClassifier(), a2.getClassifier())
130 && Objects.equals(a1.getScope(), a2.getScope())
131 && Objects.equals(a1.getDependencyFilter(), a2.getDependencyFilter())
132 && a1.isOptional() == a2.isOptional();
133 }
134
135 private static int repositoryHashCode(ArtifactRepository repository) {
136 int result = 17;
137 result = 31 * result + (repository.getId() != null ? repository.getId().hashCode() : 0);
138 return result;
139 }
140
141 private static int repositoriesHashCode(List<ArtifactRepository> repositories) {
142 int result = 17;
143 for (ArtifactRepository repository : repositories) {
144 result = 31 * result + repositoryHashCode(repository);
145 }
146 return result;
147 }
148
149 private static boolean repositoryEquals(ArtifactRepository r1, ArtifactRepository r2) {
150 if (r1 == r2) {
151 return true;
152 }
153
154 return Objects.equals(r1.getId(), r2.getId())
155 && Objects.equals(r1.getUrl(), r2.getUrl())
156 && repositoryPolicyEquals(r1.getReleases(), r2.getReleases())
157 && repositoryPolicyEquals(r1.getSnapshots(), r2.getSnapshots());
158 }
159
160 private static boolean repositoryPolicyEquals(ArtifactRepositoryPolicy p1, ArtifactRepositoryPolicy p2) {
161 if (p1 == p2) {
162 return true;
163 }
164
165 return p1.isEnabled() == p2.isEnabled() && Objects.equals(p1.getUpdatePolicy(), p2.getUpdatePolicy());
166 }
167
168 private static boolean repositoriesEquals(List<ArtifactRepository> r1, List<ArtifactRepository> r2) {
169 if (r1.size() != r2.size()) {
170 return false;
171 }
172
173 for (Iterator<ArtifactRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); ) {
174 if (!repositoryEquals(it1.next(), it2.next())) {
175 return false;
176 }
177 }
178
179 return true;
180 }
181
182
183
184
185 public class CacheRecord {
186 private Artifact pomArtifact;
187 private Artifact relocatedArtifact;
188 private List<Artifact> artifacts;
189 private Map<String, Artifact> managedVersions;
190 private List<ArtifactRepository> remoteRepositories;
191
192 private long length;
193 private long timestamp;
194
195 CacheRecord(
196 Artifact pomArtifact,
197 Artifact relocatedArtifact,
198 Set<Artifact> artifacts,
199 Map<String, Artifact> managedVersions,
200 List<ArtifactRepository> remoteRepositories) {
201 this.pomArtifact = ArtifactUtils.copyArtifact(pomArtifact);
202 this.relocatedArtifact = ArtifactUtils.copyArtifactSafe(relocatedArtifact);
203 this.artifacts = ArtifactUtils.copyArtifacts(artifacts, new ArrayList<Artifact>());
204 this.remoteRepositories = new ArrayList<>(remoteRepositories);
205
206 this.managedVersions = managedVersions;
207 if (managedVersions != null) {
208 this.managedVersions =
209 ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<String, Artifact>());
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 =
277 ArtifactUtils.copyArtifacts(cacheRecord.getArtifacts(), new LinkedHashSet<Artifact>());
278 Map<String, Artifact> managedVersions = cacheRecord.getManagedVersions();
279 if (managedVersions != null) {
280 managedVersions = ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<String, Artifact>());
281 }
282 return new ResolutionGroup(
283 pomArtifact, relocatedArtifact, artifacts, managedVersions, cacheRecord.getRemoteRepositories());
284 }
285
286 cache.remove(cacheKey);
287
288 return null;
289 }
290
291 public void put(
292 Artifact artifact,
293 boolean resolveManagedVersions,
294 ArtifactRepository localRepository,
295 List<ArtifactRepository> remoteRepositories,
296 ResolutionGroup result) {
297 put(newCacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories), result);
298 }
299
300 protected CacheKey newCacheKey(
301 Artifact artifact,
302 boolean resolveManagedVersions,
303 ArtifactRepository localRepository,
304 List<ArtifactRepository> remoteRepositories) {
305 return new CacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories);
306 }
307
308 protected void put(CacheKey cacheKey, ResolutionGroup result) {
309 CacheRecord cacheRecord = new CacheRecord(
310 result.getPomArtifact(),
311 result.getRelocatedArtifact(),
312 result.getArtifacts(),
313 result.getManagedVersions(),
314 result.getResolutionRepositories());
315
316 cache.put(cacheKey, cacheRecord);
317 }
318
319 public void flush() {
320 cache.clear();
321 }
322 }