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.internal.impl.model;
20  
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.LinkedHashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Objects;
28  import java.util.Set;
29  
30  import org.apache.maven.api.di.Named;
31  import org.apache.maven.api.di.Singleton;
32  import org.apache.maven.api.model.Dependency;
33  import org.apache.maven.api.model.DependencyManagement;
34  import org.apache.maven.api.model.Exclusion;
35  import org.apache.maven.api.model.Model;
36  import org.apache.maven.api.services.BuilderProblem.Severity;
37  import org.apache.maven.api.services.ModelBuilderRequest;
38  import org.apache.maven.api.services.ModelProblem.Version;
39  import org.apache.maven.api.services.ModelProblemCollector;
40  import org.apache.maven.api.services.model.*;
41  
42  /**
43   * Handles the import of dependency management from other models into the target model.
44   *
45   */
46  @Named
47  @Singleton
48  public class DefaultDependencyManagementImporter implements DependencyManagementImporter {
49  
50      @Override
51      public Model importManagement(
52              Model target,
53              List<? extends DependencyManagement> sources,
54              ModelBuilderRequest request,
55              ModelProblemCollector problems) {
56          if (sources != null && !sources.isEmpty()) {
57              Map<String, Dependency> dependencies = new LinkedHashMap<>();
58  
59              DependencyManagement depMgmt = target.getDependencyManagement();
60  
61              if (depMgmt != null) {
62                  for (Dependency dependency : depMgmt.getDependencies()) {
63                      dependencies.put(dependency.getManagementKey(), dependency);
64                  }
65              } else {
66                  depMgmt = DependencyManagement.newInstance();
67              }
68  
69              Set<String> directDependencies = new HashSet<>(dependencies.keySet());
70  
71              for (DependencyManagement source : sources) {
72                  for (Dependency dependency : source.getDependencies()) {
73                      String key = dependency.getManagementKey();
74                      Dependency present = dependencies.putIfAbsent(key, dependency);
75                      if (present != null && !equals(dependency, present) && !directDependencies.contains(key)) {
76                          // TODO: https://issues.apache.org/jira/browse/MNG-8004
77                          problems.add(
78                                  Severity.WARNING,
79                                  Version.V40,
80                                  "Ignored POM import for: " + toString(dependency) + " as already imported "
81                                          + toString(present) + ".  Add a the conflicting managed dependency directly "
82                                          + "to the dependencyManagement section of the POM.");
83                      }
84                  }
85              }
86  
87              return target.withDependencyManagement(depMgmt.withDependencies(dependencies.values()));
88          }
89          return target;
90      }
91  
92      private String toString(Dependency dependency) {
93          StringBuilder stringBuilder = new StringBuilder();
94          stringBuilder
95                  .append(dependency.getGroupId())
96                  .append(":")
97                  .append(dependency.getArtifactId())
98                  .append(":")
99                  .append(dependency.getType());
100         if (dependency.getClassifier() != null && !dependency.getClassifier().isEmpty()) {
101             stringBuilder.append(":").append(dependency.getClassifier());
102         }
103         stringBuilder
104                 .append(":")
105                 .append(dependency.getVersion())
106                 .append("@")
107                 .append(dependency.getScope() == null ? "compile" : dependency.getScope());
108         if (dependency.isOptional()) {
109             stringBuilder.append("[optional]");
110         }
111         if (!dependency.getExclusions().isEmpty()) {
112             stringBuilder.append("[").append(dependency.getExclusions().size()).append(" exclusions]");
113         }
114         return stringBuilder.toString();
115     }
116 
117     private boolean equals(Dependency d1, Dependency d2) {
118         return Objects.equals(d1.getGroupId(), d2.getGroupId())
119                 && Objects.equals(d1.getArtifactId(), d2.getArtifactId())
120                 && Objects.equals(d1.getVersion(), d2.getVersion())
121                 && Objects.equals(d1.getType(), d2.getType())
122                 && Objects.equals(d1.getClassifier(), d2.getClassifier())
123                 && Objects.equals(d1.getScope(), d2.getScope())
124                 && Objects.equals(d1.getSystemPath(), d2.getSystemPath())
125                 && Objects.equals(d1.getOptional(), d2.getOptional())
126                 && equals(d1.getExclusions(), d2.getExclusions());
127     }
128 
129     private boolean equals(Collection<Exclusion> ce1, Collection<Exclusion> ce2) {
130         if (ce1.size() == ce2.size()) {
131             Iterator<Exclusion> i1 = ce1.iterator();
132             Iterator<Exclusion> i2 = ce2.iterator();
133             while (i1.hasNext() && i2.hasNext()) {
134                 if (!equals(i1.next(), i2.next())) {
135                     return false;
136                 }
137             }
138             return !i1.hasNext() && !i2.hasNext();
139         }
140         return false;
141     }
142 
143     private boolean equals(Exclusion e1, Exclusion e2) {
144         return Objects.equals(e1.getGroupId(), e2.getGroupId())
145                 && Objects.equals(e1.getArtifactId(), e2.getArtifactId());
146     }
147 }