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