View Javadoc
1   package org.eclipse.aether.internal.impl;
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.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Map;
28  import java.util.Properties;
29  
30  import org.eclipse.aether.RepositorySystemSession;
31  import org.eclipse.aether.artifact.Artifact;
32  import org.eclipse.aether.repository.LocalArtifactRegistration;
33  import org.eclipse.aether.repository.LocalArtifactRequest;
34  import org.eclipse.aether.repository.LocalArtifactResult;
35  import org.eclipse.aether.repository.RemoteRepository;
36  import org.eclipse.aether.spi.log.Logger;
37  import org.eclipse.aether.util.ConfigUtils;
38  
39  /**
40   * These are implementation details for enhanced local repository manager, subject to change without prior notice.
41   * Repositories from which a cached artifact was resolved are tracked in a properties file named
42   * <code>_remote.repositories</code>, with content key as filename&gt;repo_id and value as empty string. If a file has
43   * been installed in the repository, but not downloaded from a remote repository, it is tracked as empty repository id
44   * and always resolved. For example:
45   * 
46   * <pre>
47   * artifact-1.0.pom>=
48   * artifact-1.0.jar>=
49   * artifact-1.0.pom>central=
50   * artifact-1.0.jar>central=
51   * artifact-1.0.zip>central=
52   * artifact-1.0-classifier.zip>central=
53   * artifact-1.0.pom>my_repo_id=
54   * </pre>
55   * 
56   * @see EnhancedLocalRepositoryManagerFactory
57   */
58  class EnhancedLocalRepositoryManager
59      extends SimpleLocalRepositoryManager
60  {
61  
62      private static final String LOCAL_REPO_ID = "";
63  
64      private final String trackingFilename;
65  
66      private final TrackingFileManager trackingFileManager;
67  
68      public EnhancedLocalRepositoryManager( File basedir, RepositorySystemSession session )
69      {
70          super( basedir, "enhanced" );
71          String filename = ConfigUtils.getString( session, "", "aether.enhancedLocalRepository.trackingFilename" );
72          if ( filename.length() <= 0 || filename.contains( "/" ) || filename.contains( "\\" )
73              || filename.contains( ".." ) )
74          {
75              filename = "_remote.repositories";
76          }
77          trackingFilename = filename;
78          trackingFileManager = new TrackingFileManager();
79      }
80  
81      @Override
82      public EnhancedLocalRepositoryManager setLogger( Logger logger )
83      {
84          super.setLogger( logger );
85          trackingFileManager.setLogger( logger );
86          return this;
87      }
88  
89      @Override
90      public LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request )
91      {
92          String path = getPathForArtifact( request.getArtifact(), false );
93          File file = new File( getRepository().getBasedir(), path );
94  
95          LocalArtifactResult result = new LocalArtifactResult( request );
96  
97          if ( file.isFile() )
98          {
99              result.setFile( file );
100 
101             Properties props = readRepos( file );
102 
103             if ( props.get( getKey( file, LOCAL_REPO_ID ) ) != null )
104             {
105                 // artifact installed into the local repo is always accepted
106                 result.setAvailable( true );
107             }
108             else
109             {
110                 String context = request.getContext();
111                 for ( RemoteRepository repository : request.getRepositories() )
112                 {
113                     if ( props.get( getKey( file, getRepositoryKey( repository, context ) ) ) != null )
114                     {
115                         // artifact downloaded from remote repository is accepted only downloaded from request
116                         // repositories
117                         result.setAvailable( true );
118                         result.setRepository( repository );
119                         break;
120                     }
121                 }
122                 if ( !result.isAvailable() && !isTracked( props, file ) )
123                 {
124                     /*
125                      * NOTE: The artifact is present but not tracked at all, for inter-op with simple local repo, assume
126                      * the artifact was locally installed.
127                      */
128                     result.setAvailable( true );
129                 }
130             }
131         }
132 
133         return result;
134     }
135 
136     @Override
137     public void add( RepositorySystemSession session, LocalArtifactRegistration request )
138     {
139         Collection<String> repositories;
140         if ( request.getRepository() == null )
141         {
142             repositories = Collections.singleton( LOCAL_REPO_ID );
143         }
144         else
145         {
146             repositories = getRepositoryKeys( request.getRepository(), request.getContexts() );
147         }
148         addArtifact( request.getArtifact(), repositories, request.getRepository() == null );
149     }
150 
151     private Collection<String> getRepositoryKeys( RemoteRepository repository, Collection<String> contexts )
152     {
153         Collection<String> keys = new HashSet<String>();
154 
155         if ( contexts != null )
156         {
157             for ( String context : contexts )
158             {
159                 keys.add( getRepositoryKey( repository, context ) );
160             }
161         }
162 
163         return keys;
164     }
165 
166     private void addArtifact( Artifact artifact, Collection<String> repositories, boolean local )
167     {
168         if ( artifact == null )
169         {
170             throw new IllegalArgumentException( "artifact to register not specified" );
171         }
172         String path = getPathForArtifact( artifact, local );
173         File file = new File( getRepository().getBasedir(), path );
174         addRepo( file, repositories );
175     }
176 
177     private Properties readRepos( File artifactFile )
178     {
179         File trackingFile = getTrackingFile( artifactFile );
180 
181         Properties props = trackingFileManager.read( trackingFile );
182 
183         return ( props != null ) ? props : new Properties();
184     }
185 
186     private void addRepo( File artifactFile, Collection<String> repositories )
187     {
188         Map<String, String> updates = new HashMap<String, String>();
189         for ( String repository : repositories )
190         {
191             updates.put( getKey( artifactFile, repository ), "" );
192         }
193 
194         File trackingFile = getTrackingFile( artifactFile );
195 
196         trackingFileManager.update( trackingFile, updates );
197     }
198 
199     private File getTrackingFile( File artifactFile )
200     {
201         return new File( artifactFile.getParentFile(), trackingFilename );
202     }
203 
204     private String getKey( File file, String repository )
205     {
206         return file.getName() + '>' + repository;
207     }
208 
209     private boolean isTracked( Properties props, File file )
210     {
211         if ( props != null )
212         {
213             String keyPrefix = file.getName() + '>';
214             for ( Object key : props.keySet() )
215             {
216                 if ( key.toString().startsWith( keyPrefix ) )
217                 {
218                     return true;
219                 }
220             }
221         }
222         return false;
223     }
224 
225 }