View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.util.repository;
20  
21  import java.io.File;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.util.List;
25  
26  import org.eclipse.aether.RepositorySystemSession;
27  import org.eclipse.aether.artifact.Artifact;
28  import org.eclipse.aether.metadata.Metadata;
29  import org.eclipse.aether.repository.LocalArtifactRegistration;
30  import org.eclipse.aether.repository.LocalArtifactRequest;
31  import org.eclipse.aether.repository.LocalArtifactResult;
32  import org.eclipse.aether.repository.LocalMetadataRegistration;
33  import org.eclipse.aether.repository.LocalMetadataRequest;
34  import org.eclipse.aether.repository.LocalMetadataResult;
35  import org.eclipse.aether.repository.LocalRepository;
36  import org.eclipse.aether.repository.LocalRepositoryManager;
37  import org.eclipse.aether.repository.RemoteRepository;
38  import org.eclipse.aether.util.ConfigUtils;
39  
40  import static java.util.Objects.requireNonNull;
41  import static java.util.stream.Collectors.toList;
42  
43  /**
44   * A local repository manager that chains multiple local repository managers: it directs all the write operations
45   * to chain head, while uses tail for {@link #find(RepositorySystemSession, LocalArtifactRequest)} and
46   * {@link #find(RepositorySystemSession, LocalMetadataRequest)} methods only. Hence, tail is used in resolving
47   * metadata and artifacts with or without (configurable) artifact availability tracking.
48   * <p>
49   * Implementation represents itself using the head local repository manager.
50   *
51   * @since 1.9.2
52   */
53  public final class ChainedLocalRepositoryManager implements LocalRepositoryManager {
54      public static final String IGNORE_TAIL_AVAILABILITY = "aether.chainedLocalRepository.ignoreTailAvailability";
55  
56      private static final boolean DEFAULT_IGNORE_TAIL_AVAILABILITY = true;
57  
58      private final LocalRepositoryManager head;
59  
60      private final List<LocalRepositoryManager> tail;
61  
62      private final boolean ignoreTailAvailability;
63  
64      public ChainedLocalRepositoryManager(
65              LocalRepositoryManager head, List<LocalRepositoryManager> tail, boolean ignoreTailAvailability) {
66          this.head = requireNonNull(head, "head cannot be null");
67          this.tail = requireNonNull(tail, "tail cannot be null");
68          this.ignoreTailAvailability = ignoreTailAvailability;
69      }
70  
71      public ChainedLocalRepositoryManager(
72              LocalRepositoryManager head, List<LocalRepositoryManager> tail, RepositorySystemSession session) {
73          this.head = requireNonNull(head, "head cannot be null");
74          this.tail = requireNonNull(tail, "tail cannot be null");
75          this.ignoreTailAvailability =
76                  ConfigUtils.getBoolean(session, DEFAULT_IGNORE_TAIL_AVAILABILITY, IGNORE_TAIL_AVAILABILITY);
77      }
78  
79      @Override
80      public LocalRepository getRepository() {
81          return head.getRepository();
82      }
83  
84      @Override
85      public String getPathForLocalArtifact(Artifact artifact) {
86          return head.getPathForLocalArtifact(artifact);
87      }
88  
89      @Override
90      public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
91          return head.getPathForRemoteArtifact(artifact, repository, context);
92      }
93  
94      @Override
95      public String getPathForLocalMetadata(Metadata metadata) {
96          return head.getPathForLocalMetadata(metadata);
97      }
98  
99      @Override
100     public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
101         return head.getPathForRemoteMetadata(metadata, repository, context);
102     }
103 
104     @Override
105     public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
106         LocalArtifactResult result = head.find(session, request);
107         if (result.isAvailable()) {
108             return result;
109         }
110 
111         for (LocalRepositoryManager lrm : tail) {
112             result = lrm.find(session, request);
113             if (result.getFile() != null) {
114                 if (ignoreTailAvailability) {
115                     result.setAvailable(true);
116                     return result;
117                 } else if (result.isAvailable()) {
118                     return result;
119                 }
120             }
121         }
122         return new LocalArtifactResult(request);
123     }
124 
125     @Override
126     public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
127         String artifactPath;
128         if (request.getRepository() != null) {
129             artifactPath = getPathForRemoteArtifact(request.getArtifact(), request.getRepository(), "check");
130         } else {
131             artifactPath = getPathForLocalArtifact(request.getArtifact());
132         }
133 
134         Path file = new File(head.getRepository().getBasedir(), artifactPath).toPath();
135         if (Files.isRegularFile(file)) {
136             head.add(session, request);
137         }
138     }
139 
140     @Override
141     public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
142         LocalMetadataResult result = head.find(session, request);
143         if (result.getFile() != null) {
144             return result;
145         }
146 
147         for (LocalRepositoryManager lrm : tail) {
148             result = lrm.find(session, request);
149             if (result.getFile() != null) {
150                 return result;
151             }
152         }
153         return new LocalMetadataResult(request);
154     }
155 
156     @Override
157     public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
158         String metadataPath;
159         if (request.getRepository() != null) {
160             metadataPath = getPathForRemoteMetadata(request.getMetadata(), request.getRepository(), "check");
161         } else {
162             metadataPath = getPathForLocalMetadata(request.getMetadata());
163         }
164 
165         Path file = new File(head.getRepository().getBasedir(), metadataPath).toPath();
166         if (Files.isRegularFile(file)) {
167             head.add(session, request);
168         }
169     }
170 
171     @Override
172     public String toString() {
173         return head.getRepository().toString()
174                 + tail.stream().map(LocalRepositoryManager::getRepository).collect(toList());
175     }
176 }