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.apache.maven.artifact.repository;
20  
21  import java.io.File;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Objects;
25  
26  import org.apache.maven.RepositoryUtils;
27  import org.apache.maven.artifact.metadata.ArtifactMetadata;
28  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
29  import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
30  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
31  import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
32  import org.apache.maven.repository.Proxy;
33  import org.eclipse.aether.DefaultRepositorySystemSession;
34  import org.eclipse.aether.RepositorySystem;
35  import org.eclipse.aether.RepositorySystemSession;
36  import org.eclipse.aether.artifact.Artifact;
37  import org.eclipse.aether.metadata.Metadata;
38  import org.eclipse.aether.repository.LocalArtifactRegistration;
39  import org.eclipse.aether.repository.LocalArtifactRequest;
40  import org.eclipse.aether.repository.LocalArtifactResult;
41  import org.eclipse.aether.repository.LocalMetadataRegistration;
42  import org.eclipse.aether.repository.LocalMetadataRequest;
43  import org.eclipse.aether.repository.LocalMetadataResult;
44  import org.eclipse.aether.repository.LocalRepository;
45  import org.eclipse.aether.repository.LocalRepositoryManager;
46  import org.eclipse.aether.repository.RemoteRepository;
47  
48  /**
49   * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
50   * of the public API. In particular, this class can be changed or deleted without prior notice.
51   *
52   * @author Benjamin Bentmann
53   */
54  public class LegacyLocalRepositoryManager implements LocalRepositoryManager {
55  
56      private final ArtifactRepository delegate;
57  
58      private final LocalRepository repo;
59  
60      private final boolean realLocalRepo;
61  
62      public static RepositorySystemSession overlay(
63              ArtifactRepository repository, RepositorySystemSession session, RepositorySystem system) {
64          if (repository == null || repository.getBasedir() == null) {
65              return session;
66          }
67  
68          LocalRepositoryManager lrm = session.getLocalRepositoryManager();
69          if (lrm != null
70                  && lrm.getRepository()
71                          .getBasePath()
72                          .equals(DefaultRepositorySystemSessionFactory.resolve(repository.getBasedir()))) {
73              return session;
74          }
75          if (repository.getLayout() instanceof DefaultRepositoryLayout) {
76              return new DefaultRepositorySystemSession(session)
77                      .setLocalRepositoryManager(DefaultRepositorySystemSessionFactory.setUpLocalRepositoryManager(
78                              repository.getBasedir(), system, session));
79          } else {
80              return new DefaultRepositorySystemSession(session)
81                      .setLocalRepositoryManager(new LegacyLocalRepositoryManager(repository));
82          }
83      }
84  
85      private LegacyLocalRepositoryManager(ArtifactRepository delegate) {
86          this.delegate = Objects.requireNonNull(delegate, "delegate cannot be null");
87  
88          ArtifactRepositoryLayout layout = delegate.getLayout();
89          repo = new LocalRepository(
90                  new File(delegate.getBasedir()),
91                  (layout != null) ? layout.getClass().getSimpleName() : "legacy");
92  
93          /*
94           * NOTE: "invoker:install" vs "appassembler:assemble": Both mojos use the artifact installer to put an artifact
95           * into a repository. In the first case, the result needs to be a proper local repository that one can use for
96           * local artifact resolution. In the second case, the result needs to precisely obey the path information of the
97           * repository's layout to allow pointing at artifacts within the repository. Unfortunately,
98           * DefaultRepositoryLayout does not correctly describe the layout of a local repository which unlike a remote
99           * repository never uses timestamps in the filename of a snapshot artifact. The discrepancy gets notable when a
100          * remotely resolved snapshot artifact gets passed into pathOf(). So producing a proper local artifact path
101          * using DefaultRepositoryLayout requires us to enforce usage of the artifact's base version. This
102          * transformation however contradicts the other use case of precisely obeying the repository's layout. The below
103          * flag tries to detect which use case applies to make both plugins happy.
104          */
105         realLocalRepo = (layout instanceof DefaultRepositoryLayout) && "local".equals(delegate.getId());
106     }
107 
108     public LocalRepository getRepository() {
109         return repo;
110     }
111 
112     public String getPathForLocalArtifact(Artifact artifact) {
113         if (realLocalRepo) {
114             return delegate.pathOf(RepositoryUtils.toArtifact(artifact.setVersion(artifact.getBaseVersion())));
115         }
116         return delegate.pathOf(RepositoryUtils.toArtifact(artifact));
117     }
118 
119     public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
120         return delegate.pathOf(RepositoryUtils.toArtifact(artifact));
121     }
122 
123     public String getPathForLocalMetadata(Metadata metadata) {
124         return delegate.pathOfLocalRepositoryMetadata(new ArtifactMetadataAdapter(metadata), delegate);
125     }
126 
127     public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
128         return delegate.pathOfLocalRepositoryMetadata(
129                 new ArtifactMetadataAdapter(metadata), new ArtifactRepositoryAdapter(repository));
130     }
131 
132     public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
133         String path = getPathForLocalArtifact(request.getArtifact());
134         File file = new File(getRepository().getBasedir(), path);
135 
136         LocalArtifactResult result = new LocalArtifactResult(request);
137         if (file.isFile()) {
138             result.setFile(file);
139             result.setAvailable(true);
140         }
141 
142         return result;
143     }
144 
145     public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
146         Metadata metadata = request.getMetadata();
147 
148         String path;
149         if (request.getRepository() == null) {
150             path = getPathForLocalMetadata(metadata);
151         } else {
152             path = getPathForRemoteMetadata(metadata, request.getRepository(), request.getContext());
153         }
154 
155         File file = new File(getRepository().getBasedir(), path);
156 
157         LocalMetadataResult result = new LocalMetadataResult(request);
158         if (file.isFile()) {
159             result.setFile(file);
160         }
161 
162         return result;
163     }
164 
165     public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
166         // noop
167     }
168 
169     public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
170         // noop
171     }
172 
173     static class ArtifactMetadataAdapter implements ArtifactMetadata {
174 
175         private final Metadata metadata;
176 
177         ArtifactMetadataAdapter(Metadata metadata) {
178             this.metadata = metadata;
179         }
180 
181         public boolean storedInArtifactVersionDirectory() {
182             return metadata.getVersion().length() > 0;
183         }
184 
185         public boolean storedInGroupDirectory() {
186             return metadata.getArtifactId().length() <= 0;
187         }
188 
189         public String getGroupId() {
190             return nullify(metadata.getGroupId());
191         }
192 
193         public String getArtifactId() {
194             return nullify(metadata.getArtifactId());
195         }
196 
197         public String getBaseVersion() {
198             return nullify(metadata.getVersion());
199         }
200 
201         private String nullify(String str) {
202             return (str == null || str.length() <= 0) ? null : str;
203         }
204 
205         public Object getKey() {
206             return metadata.toString();
207         }
208 
209         public String getRemoteFilename() {
210             return metadata.getType();
211         }
212 
213         public String getLocalFilename(ArtifactRepository repository) {
214             return insertRepositoryKey(getRemoteFilename(), validateRepositoryKey(repository.getKey()));
215         }
216 
217         private String insertRepositoryKey(String filename, String repositoryKey) {
218             String result;
219             int idx = filename.indexOf('.');
220             if (idx < 0) {
221                 result = filename + '-' + repositoryKey;
222             } else {
223                 result = filename.substring(0, idx) + '-' + repositoryKey + filename.substring(idx);
224             }
225             return result;
226         }
227 
228         /**
229          * The repository key (its id) is used verbatim as part of a local file name, so it must lie within
230          * the usual coordinate character set.
231          */
232         private static String validateRepositoryKey(String key) {
233             if (key == null || key.isEmpty()) {
234                 return key;
235             }
236             if (isInvalidPathToken(key)) {
237                 throw new IllegalArgumentException("Invalid repository key '" + key + "'");
238             }
239             return key;
240         }
241 
242         private static boolean isInvalidPathToken(String value) {
243             if ("..".equals(value) || value.indexOf('/') >= 0 || value.indexOf('\\') >= 0 || value.indexOf(':') >= 0) {
244                 return true;
245             }
246             for (int i = 0; i < value.length(); i++) {
247                 if (Character.isISOControl(value.charAt(i))) {
248                     return true;
249                 }
250             }
251             return false;
252         }
253 
254         public void merge(org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata) {
255             // not used
256         }
257 
258         public void merge(ArtifactMetadata metadata) {
259             // not used
260         }
261 
262         public void storeInLocalRepository(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
263                 throws RepositoryMetadataStoreException {
264             // not used
265         }
266 
267         public String extendedToString() {
268             return metadata.toString();
269         }
270     }
271 
272     static class ArtifactRepositoryAdapter implements ArtifactRepository {
273 
274         private final RemoteRepository repository;
275 
276         ArtifactRepositoryAdapter(RemoteRepository repository) {
277             this.repository = repository;
278         }
279 
280         public String pathOf(org.apache.maven.artifact.Artifact artifact) {
281             return null;
282         }
283 
284         public String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata) {
285             return null;
286         }
287 
288         public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
289             return null;
290         }
291 
292         public String getUrl() {
293             return repository.getUrl();
294         }
295 
296         public void setUrl(String url) {}
297 
298         public String getBasedir() {
299             return null;
300         }
301 
302         public String getProtocol() {
303             return repository.getProtocol();
304         }
305 
306         public String getId() {
307             return repository.getId();
308         }
309 
310         public void setId(String id) {}
311 
312         public ArtifactRepositoryPolicy getSnapshots() {
313             return null;
314         }
315 
316         public void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy policy) {}
317 
318         public ArtifactRepositoryPolicy getReleases() {
319             return null;
320         }
321 
322         public void setReleaseUpdatePolicy(ArtifactRepositoryPolicy policy) {}
323 
324         public ArtifactRepositoryLayout getLayout() {
325             return null;
326         }
327 
328         public void setLayout(ArtifactRepositoryLayout layout) {}
329 
330         public String getKey() {
331             return getId();
332         }
333 
334         public boolean isUniqueVersion() {
335             return true;
336         }
337 
338         public boolean isBlacklisted() {
339             return false;
340         }
341 
342         public void setBlacklisted(boolean blackListed) {}
343 
344         public org.apache.maven.artifact.Artifact find(org.apache.maven.artifact.Artifact artifact) {
345             return null;
346         }
347 
348         public List<String> findVersions(org.apache.maven.artifact.Artifact artifact) {
349             return Collections.emptyList();
350         }
351 
352         public boolean isProjectAware() {
353             return false;
354         }
355 
356         public void setAuthentication(Authentication authentication) {}
357 
358         public Authentication getAuthentication() {
359             return null;
360         }
361 
362         public void setProxy(Proxy proxy) {}
363 
364         public Proxy getProxy() {
365             return null;
366         }
367 
368         public List<ArtifactRepository> getMirroredRepositories() {
369             return Collections.emptyList();
370         }
371 
372         public void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories) {}
373 
374         public boolean isBlocked() {
375             return false;
376         }
377 
378         public void setBlocked(boolean blocked) {}
379     }
380 }