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.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
44 implements MavenMetadataCache
45 {
46
47 protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<>();
48
49
50
51
52 public static class CacheKey
53 {
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( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
61 List<ArtifactRepository> remoteRepositories )
62 {
63 File file = artifact.getFile();
64 this.artifact = ArtifactUtils.copyArtifact( artifact );
65 if ( "pom".equals( artifact.getType() ) && file != null )
66 {
67 pomHash = file.getPath().hashCode() + file.lastModified();
68 }
69 else
70 {
71 pomHash = 0;
72 }
73 this.resolveManagedVersions = resolveManagedVersions;
74 this.repositories.add( localRepository );
75 this.repositories.addAll( remoteRepositories );
76
77 int hash = 17;
78 hash = hash * 31 + artifactHashCode( artifact );
79 hash = hash * 31 + ( resolveManagedVersions ? 1 : 2 );
80 hash = hash * 31 + repositoriesHashCode( repositories );
81 this.hashCode = hash;
82 }
83
84 @Override
85 public int hashCode()
86 {
87 return hashCode;
88 }
89
90 @Override
91 public boolean equals( Object o )
92 {
93 if ( o == this )
94 {
95 return true;
96 }
97
98 if ( !( o instanceof CacheKey ) )
99 {
100 return false;
101 }
102
103 CacheKey other = (CacheKey) o;
104
105 return pomHash == other.pomHash && artifactEquals( artifact, other.artifact )
106 && resolveManagedVersions == other.resolveManagedVersions
107 && repositoriesEquals( repositories, other.repositories );
108 }
109 }
110
111 private static int artifactHashCode( Artifact a )
112 {
113 int result = 17;
114 result = 31 * result + a.getGroupId().hashCode();
115 result = 31 * result + a.getArtifactId().hashCode();
116 result = 31 * result + a.getType().hashCode();
117 if ( a.getVersion() != null )
118 {
119 result = 31 * result + a.getVersion().hashCode();
120 }
121 result = 31 * result + ( a.getClassifier() != null ? a.getClassifier().hashCode() : 0 );
122 result = 31 * result + ( a.getScope() != null ? a.getScope().hashCode() : 0 );
123 result = 31 * result + ( a.getDependencyFilter() != null ? a.getDependencyFilter().hashCode() : 0 );
124 result = 31 * result + ( a.isOptional() ? 1 : 0 );
125 return result;
126 }
127
128 private static boolean artifactEquals( Artifact a1, Artifact a2 )
129 {
130 if ( a1 == a2 )
131 {
132 return true;
133 }
134
135 return eq( a1.getGroupId(), a2.getGroupId() )
136 && eq( a1.getArtifactId(), a2.getArtifactId() )
137 && eq( a1.getType(), a2.getType() )
138 && eq( a1.getVersion(), a2.getVersion() )
139 && eq( a1.getClassifier(), a2.getClassifier() )
140 && eq( a1.getScope(), a2.getScope() )
141 && eq( a1.getDependencyFilter(), a2.getDependencyFilter() )
142 && a1.isOptional() == a2.isOptional();
143 }
144
145 private static int repositoryHashCode( ArtifactRepository repository )
146 {
147 int result = 17;
148 result = 31 * result + ( repository.getId() != null ? repository.getId().hashCode() : 0 );
149 return result;
150 }
151
152 private static int repositoriesHashCode( List<ArtifactRepository> repositories )
153 {
154 int result = 17;
155 for ( ArtifactRepository repository : repositories )
156 {
157 result = 31 * result + repositoryHashCode( repository );
158 }
159 return result;
160 }
161
162 private static boolean repositoryEquals( ArtifactRepository r1, ArtifactRepository r2 )
163 {
164 if ( r1 == r2 )
165 {
166 return true;
167 }
168
169 return eq( r1.getId(), r2.getId() ) && eq( r1.getUrl(), r2.getUrl() )
170 && repositoryPolicyEquals( r1.getReleases(), r2.getReleases() )
171 && repositoryPolicyEquals( r1.getSnapshots(), r2.getSnapshots() );
172 }
173
174 private static boolean repositoryPolicyEquals( ArtifactRepositoryPolicy p1, ArtifactRepositoryPolicy p2 )
175 {
176 if ( p1 == p2 )
177 {
178 return true;
179 }
180
181 return p1.isEnabled() == p2.isEnabled() && eq( p1.getUpdatePolicy(), p2.getUpdatePolicy() );
182 }
183
184 private static boolean repositoriesEquals( List<ArtifactRepository> r1, List<ArtifactRepository> r2 )
185 {
186 if ( r1.size() != r2.size() )
187 {
188 return false;
189 }
190
191 for ( Iterator<ArtifactRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); )
192 {
193 if ( !repositoryEquals( it1.next(), it2.next() ) )
194 {
195 return false;
196 }
197 }
198
199 return true;
200 }
201
202 private static <T> boolean eq( T s1, T s2 )
203 {
204 return s1 != null ? s1.equals( s2 ) : s2 == null;
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<Artifact>() );
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<String, Artifact>() );
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<Artifact>() );
317 Map<String, Artifact> managedVersions = cacheRecord.getManagedVersions();
318 if ( managedVersions != null )
319 {
320 managedVersions = ArtifactUtils.copyArtifacts( managedVersions, new LinkedHashMap<String, Artifact>() );
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 }