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