3232import java .nio .file .Path ;
3333import java .util .ArrayList ;
3434import java .util .Arrays ;
35+ import java .util .Collections ;
3536import java .util .HashMap ;
3637import java .util .List ;
3738import java .util .Optional ;
3839import java .util .concurrent .ConcurrentHashMap ;
3940import javax .inject .Inject ;
4041import javax .inject .Named ;
4142import javax .inject .Singleton ;
43+ import org .eclipse .aether .RepositorySystem ;
4244import org .eclipse .aether .RepositorySystemSession ;
4345import org .eclipse .aether .artifact .Artifact ;
46+ import org .eclipse .aether .metadata .DefaultMetadata ;
4447import org .eclipse .aether .metadata .Metadata ;
4548import org .eclipse .aether .repository .RemoteRepository ;
49+ import org .eclipse .aether .resolution .MetadataRequest ;
50+ import org .eclipse .aether .resolution .MetadataResult ;
4651import org .eclipse .aether .spi .connector .filter .RemoteRepositoryFilter ;
4752import org .eclipse .aether .spi .connector .layout .RepositoryLayout ;
4853import org .eclipse .aether .spi .connector .layout .RepositoryLayoutProvider ;
4954import org .eclipse .aether .transfer .NoRepositoryLayoutException ;
50- import org .slf4j .Logger ;
51- import org .slf4j .LoggerFactory ;
5255
5356/**
5457 * Remote repository filter source filtering on path prefixes. It is backed by a file that lists all allowed path
@@ -82,7 +85,7 @@ public final class PrefixesRemoteRepositoryFilterSource extends RemoteRepository
8285
8386 static final String PREFIXES_FILE_SUFFIX = ".txt" ;
8487
85- private static final Logger LOGGER = LoggerFactory . getLogger ( PrefixesRemoteRepositoryFilterSource . class ) ;
88+ private final RepositorySystem repositorySystem ;
8689
8790 private final RepositoryLayoutProvider repositoryLayoutProvider ;
8891
@@ -91,8 +94,10 @@ public final class PrefixesRemoteRepositoryFilterSource extends RemoteRepository
9194 private final ConcurrentHashMap <RemoteRepository , RepositoryLayout > layouts ;
9295
9396 @ Inject
94- public PrefixesRemoteRepositoryFilterSource (RepositoryLayoutProvider repositoryLayoutProvider ) {
97+ public PrefixesRemoteRepositoryFilterSource (
98+ RepositorySystem repositorySystem , RepositoryLayoutProvider repositoryLayoutProvider ) {
9599 super (NAME );
100+ this .repositorySystem = requireNonNull (repositorySystem );
96101 this .repositoryLayoutProvider = requireNonNull (repositoryLayoutProvider );
97102 this .prefixes = new ConcurrentHashMap <>();
98103 this .layouts = new ConcurrentHashMap <>();
@@ -102,7 +107,7 @@ public PrefixesRemoteRepositoryFilterSource(RepositoryLayoutProvider repositoryL
102107 public RemoteRepositoryFilter getRemoteRepositoryFilter (RepositorySystemSession session ) {
103108 Optional <Session > so = SessionUtils .mayGetSession (session );
104109 if (so .isPresent () && isEnabled (session )) {
105- return new PrefixesFilter (session , getBasedir (session , false ));
110+ return new PrefixesFilter (so . orElseThrow ( J8Utils . OET ), session , getBasedir (session , false ));
106111 }
107112 return null ;
108113 }
@@ -122,21 +127,35 @@ private RepositoryLayout cacheLayout(RepositorySystemSession session, RemoteRepo
122127 });
123128 }
124129
130+ private final ConcurrentHashMap <RemoteRepository , Boolean > ongoingUpdates = new ConcurrentHashMap <>();
131+
125132 /**
126133 * Caches prefixes instances for remote repository.
127134 */
128- private Node cacheNode (Path basedir , RemoteRepository remoteRepository ) {
129- return prefixes .computeIfAbsent (remoteRepository , r -> loadRepositoryPrefixes (basedir , remoteRepository ));
135+ private Node cacheNode (RepositorySystemSession session , Path basedir , RemoteRepository remoteRepository ) {
136+ if (!remoteRepository .isBlocked () && null == ongoingUpdates .putIfAbsent (remoteRepository , Boolean .TRUE )) {
137+ try {
138+ return prefixes .computeIfAbsent (
139+ remoteRepository , r -> loadRepositoryPrefixes (session , basedir , remoteRepository ));
140+ } finally {
141+ ongoingUpdates .remove (remoteRepository );
142+ }
143+ }
144+ return NOT_PRESENT_NODE ;
130145 }
131146
132147 /**
133148 * Loads prefixes file and preprocesses it into {@link Node} instance.
134149 */
135- private Node loadRepositoryPrefixes (Path baseDir , RemoteRepository remoteRepository ) {
136- Path filePath = baseDir .resolve (PREFIXES_FILE_PREFIX + remoteRepository .getId () + PREFIXES_FILE_SUFFIX );
150+ private Node loadRepositoryPrefixes (
151+ RepositorySystemSession session , Path baseDir , RemoteRepository remoteRepository ) {
152+ Path filePath = resolvePrefixesFromRemoteRepository (session , remoteRepository );
153+ if (filePath == null ) {
154+ filePath = baseDir .resolve (PREFIXES_FILE_PREFIX + remoteRepository .getId () + PREFIXES_FILE_SUFFIX );
155+ }
137156 if (Files .isReadable (filePath )) {
138157 try (BufferedReader reader = Files .newBufferedReader (filePath , StandardCharsets .UTF_8 )) {
139- LOGGER .debug (
158+ logger .debug (
140159 "Loading prefixes for remote repository {} from file '{}'" , remoteRepository .getId (), filePath );
141160 Node root = new Node ("" );
142161 String prefix ;
@@ -150,31 +169,49 @@ private Node loadRepositoryPrefixes(Path baseDir, RemoteRepository remoteReposit
150169 }
151170 }
152171 }
153- LOGGER .info ("Heimdall loaded {} prefixes for remote repository {}" , lines , remoteRepository .getId ());
172+ logger .info ("Heimdall loaded {} prefixes for remote repository {}" , lines , remoteRepository .getId ());
154173 return root ;
155174 } catch (FileNotFoundException e ) {
156175 // strange: we tested for it above, still, we should not fail
157176 } catch (IOException e ) {
158177 throw new UncheckedIOException (e );
159178 }
160179 }
161- LOGGER .debug ("Prefix file for remote repository {} not found at '{}'" , remoteRepository , filePath );
180+ logger .debug ("Prefix file for remote repository {} not found at '{}'" , remoteRepository , filePath );
162181 return NOT_PRESENT_NODE ;
163182 }
164183
165- private class PrefixesFilter implements RemoteRepositoryFilter {
166- private final RepositorySystemSession session ;
184+ private Path resolvePrefixesFromRemoteRepository (
185+ RepositorySystemSession session , RemoteRepository remoteRepository ) {
186+ MetadataRequest request =
187+ new MetadataRequest (new DefaultMetadata (".meta/prefixes.txt" , Metadata .Nature .RELEASE_OR_SNAPSHOT ));
188+ request .setRepository (remoteRepository );
189+ request .setDeleteLocalCopyIfMissing (true );
190+ request .setFavorLocalRepository (true );
191+ MetadataResult result = repositorySystem
192+ .resolveMetadata (session , Collections .singleton (request ))
193+ .get (0 );
194+ if (result .isResolved ()) {
195+ return result .getMetadata ().getFile ().toPath ();
196+ } else {
197+ return null ;
198+ }
199+ }
167200
201+ private class PrefixesFilter implements RemoteRepositoryFilter {
202+ private final Session session ;
203+ private final RepositorySystemSession repoSession ;
168204 private final Path basedir ;
169205
170- private PrefixesFilter (RepositorySystemSession session , Path basedir ) {
206+ private PrefixesFilter (Session session , RepositorySystemSession repoSession , Path basedir ) {
171207 this .session = session ;
208+ this .repoSession = repoSession ;
172209 this .basedir = basedir ;
173210 }
174211
175212 @ Override
176213 public Result acceptArtifact (RemoteRepository remoteRepository , Artifact artifact ) {
177- RepositoryLayout repositoryLayout = cacheLayout (session , remoteRepository );
214+ RepositoryLayout repositoryLayout = cacheLayout (repoSession , remoteRepository );
178215 if (repositoryLayout == null ) {
179216 return new SimpleResult (true , "Unsupported layout: " + remoteRepository );
180217 }
@@ -185,7 +222,7 @@ public Result acceptArtifact(RemoteRepository remoteRepository, Artifact artifac
185222
186223 @ Override
187224 public Result acceptMetadata (RemoteRepository remoteRepository , Metadata metadata ) {
188- RepositoryLayout repositoryLayout = cacheLayout (session , remoteRepository );
225+ RepositoryLayout repositoryLayout = cacheLayout (repoSession , remoteRepository );
189226 if (repositoryLayout == null ) {
190227 return new SimpleResult (true , "Unsupported layout: " + remoteRepository );
191228 }
@@ -195,7 +232,10 @@ public Result acceptMetadata(RemoteRepository remoteRepository, Metadata metadat
195232 }
196233
197234 private Result acceptPrefix (RemoteRepository remoteRepository , String path ) {
198- Node root = cacheNode (basedir , remoteRepository );
235+ if (!isEnabled (repoSession )) {
236+ return NOT_PRESENT_RESULT ;
237+ }
238+ Node root = cacheNode (repoSession , basedir , remoteRepository );
199239 if (NOT_PRESENT_NODE == root ) {
200240 return NOT_PRESENT_RESULT ;
201241 }
@@ -243,12 +283,7 @@ public boolean isLeaf() {
243283 }
244284
245285 public Node addSibling (String name ) {
246- Node sibling = siblings .get (name );
247- if (sibling == null ) {
248- sibling = new Node (name );
249- siblings .put (name , sibling );
250- }
251- return sibling ;
286+ return siblings .computeIfAbsent (name , Node ::new );
252287 }
253288
254289 public Node getSibling (String name ) {
0 commit comments