View Javadoc
1   package org.apache.maven.project.artifact;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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                     // 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 }