001 package org.apache.maven.project.artifact;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.util.ArrayList;
024 import java.util.Iterator;
025 import java.util.LinkedHashMap;
026 import java.util.LinkedHashSet;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.Set;
030 import java.util.concurrent.ConcurrentHashMap;
031
032 import org.apache.maven.artifact.Artifact;
033 import org.apache.maven.artifact.ArtifactUtils;
034 import org.apache.maven.artifact.metadata.ResolutionGroup;
035 import org.apache.maven.artifact.repository.ArtifactRepository;
036 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
037 import org.codehaus.plexus.component.annotations.Component;
038
039 @Component( role = MavenMetadataCache.class )
040 public class DefaultMavenMetadataCache
041 implements MavenMetadataCache
042 {
043
044 protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<CacheKey, CacheRecord>();
045
046 public static class CacheKey
047 {
048 private final Artifact artifact;
049 private final long pomHash;
050 private final boolean resolveManagedVersions;
051 private final List<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
052 private final int hashCode;
053
054 public CacheKey( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
055 List<ArtifactRepository> remoteRepositories )
056 {
057 File file = artifact.getFile();
058 this.artifact = ArtifactUtils.copyArtifact( artifact );
059 if ( "pom".equals( artifact.getType() ) && file != null )
060 {
061 pomHash = file.getPath().hashCode() + file.lastModified();
062 }
063 else
064 {
065 pomHash = 0;
066 }
067 this.resolveManagedVersions = resolveManagedVersions;
068 this.repositories.add( localRepository );
069 this.repositories.addAll( remoteRepositories );
070
071 int hash = 17;
072 hash = hash * 31 + artifactHashCode( artifact );
073 hash = hash * 31 + ( resolveManagedVersions ? 1 : 2 );
074 hash = hash * 31 + repositoriesHashCode( repositories );
075 this.hashCode = hash;
076 }
077
078 @Override
079 public int hashCode()
080 {
081 return hashCode;
082 }
083
084 @Override
085 public boolean equals( Object o )
086 {
087 if ( o == this )
088 {
089 return true;
090 }
091
092 if ( !( o instanceof CacheKey ) )
093 {
094 return false;
095 }
096
097 CacheKey other = (CacheKey) o;
098
099 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<ArtifactRepository>( 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 // if the POM didn't exist, retry if any repo is configured to always update
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 }