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