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;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Objects;
28  import java.util.Optional;
29  import java.util.stream.Collectors;
30  
31  import org.apache.maven.artifact.handler.ArtifactHandler;
32  import org.apache.maven.artifact.handler.DefaultArtifactHandler;
33  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
34  import org.apache.maven.artifact.repository.ArtifactRepository;
35  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
36  import org.eclipse.aether.RepositorySystemSession;
37  import org.eclipse.aether.artifact.Artifact;
38  import org.eclipse.aether.artifact.ArtifactProperties;
39  import org.eclipse.aether.artifact.ArtifactType;
40  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
41  import org.eclipse.aether.artifact.DefaultArtifact;
42  import org.eclipse.aether.artifact.DefaultArtifactType;
43  import org.eclipse.aether.graph.Dependency;
44  import org.eclipse.aether.graph.DependencyFilter;
45  import org.eclipse.aether.graph.DependencyNode;
46  import org.eclipse.aether.graph.Exclusion;
47  import org.eclipse.aether.repository.Authentication;
48  import org.eclipse.aether.repository.Proxy;
49  import org.eclipse.aether.repository.RemoteRepository;
50  import org.eclipse.aether.repository.RepositoryPolicy;
51  import org.eclipse.aether.repository.WorkspaceReader;
52  import org.eclipse.aether.repository.WorkspaceRepository;
53  import org.eclipse.aether.util.repository.AuthenticationBuilder;
54  
55  /**
56   * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
57   * of the public API. In particular, this class can be changed or deleted without prior notice.
58   *
59   * @author Benjamin Bentmann
60   */
61  public class RepositoryUtils {
62  
63      private static String nullify(String string) {
64          return (string == null || string.length() <= 0) ? null : string;
65      }
66  
67      /**
68       * Converts a {@link Dependency} object to a Maven {@link org.apache.maven.artifact.Artifact} object.
69       *
70       * @param dependency the dependency to be converted; may be null. If null, the method returns null.
71       * @return the equivalent {@link org.apache.maven.artifact.Artifact} object with the same attributes as the
72       *         provided dependency, or null if the input dependency is null.
73       *
74       * @since 3.10.0
75       */
76      public static org.apache.maven.artifact.Artifact toArtifact(Dependency dependency) {
77          if (dependency == null) {
78              return null;
79          }
80  
81          org.apache.maven.artifact.Artifact result = toArtifact(dependency.getArtifact());
82          result.setScope(dependency.getScope());
83          result.setOptional(dependency.isOptional());
84  
85          return result;
86      }
87  
88      public static org.apache.maven.artifact.Artifact toArtifact(Artifact artifact) {
89          if (artifact == null) {
90              return null;
91          }
92  
93          ArtifactHandler handler = newHandler(artifact);
94  
95          /*
96           * NOTE: From Artifact.hasClassifier(), an empty string and a null both denote "no classifier". However, some
97           * plugins only check for null, so be sure to nullify an empty classifier.
98           */
99          org.apache.maven.artifact.Artifact result = new org.apache.maven.artifact.DefaultArtifact(
100                 artifact.getGroupId(),
101                 artifact.getArtifactId(),
102                 artifact.getVersion(),
103                 null,
104                 artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()),
105                 nullify(artifact.getClassifier()),
106                 handler);
107 
108         result.setFile(artifact.getFile());
109         result.setResolved(artifact.getFile() != null);
110 
111         List<String> trail = new ArrayList<>(1);
112         trail.add(result.getId());
113         result.setDependencyTrail(trail);
114 
115         return result;
116     }
117 
118     public static void toArtifacts(
119             Collection<org.apache.maven.artifact.Artifact> artifacts,
120             Collection<? extends DependencyNode> nodes,
121             List<String> trail,
122             DependencyFilter filter) {
123         for (DependencyNode node : nodes) {
124             org.apache.maven.artifact.Artifact artifact = toArtifact(node.getDependency());
125 
126             List<String> nodeTrail = new ArrayList<>(trail.size() + 1);
127             nodeTrail.addAll(trail);
128             nodeTrail.add(artifact.getId());
129 
130             if (filter == null || filter.accept(node, Collections.<DependencyNode>emptyList())) {
131                 artifact.setDependencyTrail(nodeTrail);
132                 artifacts.add(artifact);
133             }
134 
135             toArtifacts(artifacts, node.getChildren(), nodeTrail, filter);
136         }
137     }
138 
139     public static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) {
140         if (artifact == null) {
141             return null;
142         }
143 
144         String version = artifact.getVersion();
145         if (version == null && artifact.getVersionRange() != null) {
146             version = artifact.getVersionRange().toString();
147         }
148 
149         Map<String, String> props = null;
150         if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
151             String localPath = (artifact.getFile() != null) ? artifact.getFile().getPath() : "";
152             props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, localPath);
153         }
154 
155         Artifact result = new DefaultArtifact(
156                 artifact.getGroupId(),
157                 artifact.getArtifactId(),
158                 artifact.getClassifier(),
159                 artifact.getArtifactHandler().getExtension(),
160                 version,
161                 props,
162                 newArtifactType(artifact.getType(), artifact.getArtifactHandler()));
163         result = result.setFile(artifact.getFile());
164 
165         return result;
166     }
167 
168     public static Dependency toDependency(
169             org.apache.maven.artifact.Artifact artifact, Collection<org.apache.maven.model.Exclusion> exclusions) {
170         if (artifact == null) {
171             return null;
172         }
173 
174         Artifact result = toArtifact(artifact);
175 
176         List<Exclusion> excl = Optional.ofNullable(exclusions).orElse(Collections.emptyList()).stream()
177                 .map(RepositoryUtils::toExclusion)
178                 .collect(Collectors.toList());
179         return new Dependency(result, artifact.getScope(), artifact.isOptional(), excl);
180     }
181 
182     public static List<RemoteRepository> toRepos(List<ArtifactRepository> repos) {
183         return Optional.ofNullable(repos).orElse(Collections.emptyList()).stream()
184                 .map(RepositoryUtils::toRepo)
185                 .collect(Collectors.toList());
186     }
187 
188     public static RemoteRepository toRepo(ArtifactRepository repo) {
189         RemoteRepository result = null;
190         if (repo != null) {
191             RemoteRepository.Builder builder =
192                     new RemoteRepository.Builder(repo.getId(), getLayout(repo), repo.getUrl());
193             builder.setSnapshotPolicy(toPolicy(repo.getSnapshots()));
194             builder.setReleasePolicy(toPolicy(repo.getReleases()));
195             builder.setAuthentication(toAuthentication(repo.getAuthentication()));
196             builder.setProxy(toProxy(repo.getProxy()));
197             builder.setMirroredRepositories(toRepos(repo.getMirroredRepositories()));
198             builder.setBlocked(repo.isBlocked());
199             result = builder.build();
200         }
201         return result;
202     }
203 
204     public static String getLayout(ArtifactRepository repo) {
205         try {
206             return repo.getLayout().getId();
207         } catch (LinkageError e) {
208             /*
209              * NOTE: getId() was added in 3.x and is as such not implemented by plugins compiled against 2.x APIs.
210              */
211             String className = repo.getLayout().getClass().getSimpleName();
212             if (className.endsWith("RepositoryLayout")) {
213                 String layout = className.substring(0, className.length() - "RepositoryLayout".length());
214                 if (layout.length() > 0) {
215                     layout = Character.toLowerCase(layout.charAt(0)) + layout.substring(1);
216                     return layout;
217                 }
218             }
219             return "";
220         }
221     }
222 
223     private static RepositoryPolicy toPolicy(ArtifactRepositoryPolicy policy) {
224         RepositoryPolicy result = null;
225         if (policy != null) {
226             result = new RepositoryPolicy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy());
227         }
228         return result;
229     }
230 
231     private static Authentication toAuthentication(org.apache.maven.artifact.repository.Authentication auth) {
232         Authentication result = null;
233         if (auth != null) {
234             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
235             authBuilder.addUsername(auth.getUsername()).addPassword(auth.getPassword());
236             authBuilder.addPrivateKey(auth.getPrivateKey(), auth.getPassphrase());
237             result = authBuilder.build();
238         }
239         return result;
240     }
241 
242     private static Proxy toProxy(org.apache.maven.repository.Proxy proxy) {
243         Proxy result = null;
244         if (proxy != null) {
245             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
246             authBuilder.addUsername(proxy.getUserName()).addPassword(proxy.getPassword());
247             result = new Proxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build());
248         }
249         return result;
250     }
251 
252     public static ArtifactHandler newHandler(Artifact artifact) {
253         String type = artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension());
254         DefaultArtifactHandler handler = new DefaultArtifactHandler(type);
255         handler.setExtension(artifact.getExtension());
256         handler.setLanguage(artifact.getProperty(ArtifactProperties.LANGUAGE, null));
257         String addedToClasspath = artifact.getProperty(ArtifactProperties.CONSTITUTES_BUILD_PATH, "");
258         handler.setAddedToClasspath(Boolean.parseBoolean(addedToClasspath));
259         String includesDependencies = artifact.getProperty(ArtifactProperties.INCLUDES_DEPENDENCIES, "");
260         handler.setIncludesDependencies(Boolean.parseBoolean(includesDependencies));
261         return handler;
262     }
263 
264     public static ArtifactType newArtifactType(String id, ArtifactHandler handler) {
265         return new DefaultArtifactType(
266                 id,
267                 handler.getExtension(),
268                 handler.getClassifier(),
269                 handler.getLanguage(),
270                 handler.isAddedToClasspath(),
271                 handler.isIncludesDependencies());
272     }
273 
274     public static Dependency toDependency(
275             org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes) {
276         ArtifactType stereotype = stereotypes.get(dependency.getType());
277         if (stereotype == null) {
278             stereotype = new DefaultArtifactType(dependency.getType());
279         }
280 
281         boolean system =
282                 dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0;
283 
284         Map<String, String> props = null;
285         if (system) {
286             props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath());
287         }
288 
289         Artifact artifact = new DefaultArtifact(
290                 dependency.getGroupId(),
291                 dependency.getArtifactId(),
292                 dependency.getClassifier(),
293                 null,
294                 dependency.getVersion(),
295                 props,
296                 stereotype);
297 
298         List<Exclusion> exclusions = dependency.getExclusions().stream()
299                 .map(RepositoryUtils::toExclusion)
300                 .collect(Collectors.toList());
301 
302         Dependency result = new Dependency(
303                 artifact,
304                 dependency.getScope(),
305                 dependency.getOptional() != null ? dependency.isOptional() : null,
306                 exclusions);
307 
308         return result;
309     }
310 
311     private static Exclusion toExclusion(org.apache.maven.model.Exclusion exclusion) {
312         return new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
313     }
314 
315     public static ArtifactTypeRegistry newArtifactTypeRegistry(ArtifactHandlerManager handlerManager) {
316         return new MavenArtifactTypeRegistry(handlerManager);
317     }
318 
319     static class MavenArtifactTypeRegistry implements ArtifactTypeRegistry {
320 
321         private final ArtifactHandlerManager handlerManager;
322 
323         MavenArtifactTypeRegistry(ArtifactHandlerManager handlerManager) {
324             this.handlerManager = handlerManager;
325         }
326 
327         public ArtifactType get(String stereotypeId) {
328             ArtifactHandler handler = handlerManager.getArtifactHandler(stereotypeId);
329             return newArtifactType(stereotypeId, handler);
330         }
331     }
332 
333     public static Collection<Artifact> toArtifacts(Collection<org.apache.maven.artifact.Artifact> artifactsToConvert) {
334         return artifactsToConvert.stream().map(RepositoryUtils::toArtifact).collect(Collectors.toList());
335     }
336 
337     public static WorkspaceRepository getWorkspace(RepositorySystemSession session) {
338         WorkspaceReader reader = session.getWorkspaceReader();
339         return (reader != null) ? reader.getRepository() : null;
340     }
341 
342     public static boolean repositoriesEquals(List<RemoteRepository> r1, List<RemoteRepository> r2) {
343         if (r1.size() != r2.size()) {
344             return false;
345         }
346 
347         for (Iterator<RemoteRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); ) {
348             if (!repositoryEquals(it1.next(), it2.next())) {
349                 return false;
350             }
351         }
352 
353         return true;
354     }
355 
356     public static int repositoriesHashCode(List<RemoteRepository> repositories) {
357         int result = 17;
358         for (RemoteRepository repository : repositories) {
359             result = 31 * result + repositoryHashCode(repository);
360         }
361         return result;
362     }
363 
364     private static int repositoryHashCode(RemoteRepository repository) {
365         int result = 17;
366         Object obj = repository.getUrl();
367         result = 31 * result + (obj != null ? obj.hashCode() : 0);
368         return result;
369     }
370 
371     private static boolean policyEquals(RepositoryPolicy p1, RepositoryPolicy p2) {
372         if (p1 == p2) {
373             return true;
374         }
375         // update policy doesn't affect contents
376         return p1.isEnabled() == p2.isEnabled() && Objects.equals(p1.getChecksumPolicy(), p2.getChecksumPolicy());
377     }
378 
379     private static boolean repositoryEquals(RemoteRepository r1, RemoteRepository r2) {
380         if (r1 == r2) {
381             return true;
382         }
383 
384         return Objects.equals(r1.getId(), r2.getId())
385                 && Objects.equals(r1.getUrl(), r2.getUrl())
386                 && policyEquals(r1.getPolicy(false), r2.getPolicy(false))
387                 && policyEquals(r1.getPolicy(true), r2.getPolicy(true));
388     }
389 }