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.repository.metadata;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.TreeSet;
28  
29  import org.apache.maven.artifact.ArtifactScopeEnum;
30  
31  /**
32   * Default conflict resolver.Implements closer newer first policy by default, but could be configured via plexus
33   *
34   */
35  @Named
36  @Singleton
37  @Deprecated
38  public class DefaultGraphConflictResolver implements GraphConflictResolver {
39      /**
40       * artifact, closer to the entry point, is selected
41       */
42      @Inject
43      protected GraphConflictResolutionPolicy policy;
44  
45      // -------------------------------------------------------------------------------------
46      // -------------------------------------------------------------------------------------
47      @Override
48      public MetadataGraph resolveConflicts(MetadataGraph graph, ArtifactScopeEnum scope)
49              throws GraphConflictResolutionException {
50          if (policy == null) {
51              throw new GraphConflictResolutionException("no GraphConflictResolutionPolicy injected");
52          }
53  
54          if (graph == null) {
55              return null;
56          }
57  
58          final MetadataGraphVertex entry = graph.getEntry();
59          if (entry == null) {
60              return null;
61          }
62  
63          if (graph.isEmpty()) {
64              throw new GraphConflictResolutionException("graph with an entry, but not vertices do not exist");
65          }
66  
67          if (graph.isEmptyEdges()) {
68              return null; // no edges - nothing to worry about
69          }
70  
71          final TreeSet<MetadataGraphVertex> vertices = graph.getVertices();
72  
73          try {
74              // edge case - single vertex graph
75              if (vertices.size() == 1) {
76                  return new MetadataGraph(entry);
77              }
78  
79              final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope(scope);
80  
81              MetadataGraph res = new MetadataGraph(vertices.size());
82              res.setVersionedVertices(false);
83              res.setScopedVertices(false);
84  
85              MetadataGraphVertex resEntry = res.addVertex(entry.getMd());
86              res.setEntry(resEntry);
87  
88              res.setScope(requestedScope);
89  
90              for (MetadataGraphVertex v : vertices) {
91                  final List<MetadataGraphEdge> ins = graph.getIncidentEdges(v);
92                  final MetadataGraphEdge edge = cleanEdges(v, ins, requestedScope);
93  
94                  if (edge == null) { // no edges - don't need this vertex anymore
95                      if (entry.equals(v)) { // unless it's an entry point.
96                          // currently processing the entry point - it should not have any entry incident edges
97                          res.getEntry().getMd().setWhy("This is a graph entry point. No links.");
98                      }
99                  } else {
100                     // fill in domain md with actual version data
101                     ArtifactMetadata md = v.getMd();
102                     ArtifactMetadata newMd = new ArtifactMetadata(
103                             md.getGroupId(),
104                             md.getArtifactId(),
105                             edge.getVersion(),
106                             md.getType(),
107                             md.getScopeAsEnum(),
108                             md.getClassifier(),
109                             edge.getArtifactUri(),
110                             edge.getSource() == null
111                                     ? ""
112                                     : edge.getSource().getMd().toString(),
113                             edge.isResolved(),
114                             edge.getTarget() == null
115                                     ? null
116                                     : edge.getTarget().getMd().getError());
117                     MetadataGraphVertex newV = res.addVertex(newMd);
118                     MetadataGraphVertex sourceV = res.addVertex(edge.getSource().getMd());
119 
120                     res.addEdge(sourceV, newV, edge);
121                 }
122             }
123             return findLinkedSubgraph(res);
124         } catch (MetadataResolutionException e) {
125             throw new GraphConflictResolutionException(e);
126         }
127     }
128 
129     // -------------------------------------------------------------------------------------
130     private MetadataGraph findLinkedSubgraph(MetadataGraph g) {
131         if (g.getVertices().size() == 1) {
132             return g;
133         }
134 
135         List<MetadataGraphVertex> visited = new ArrayList<>(g.getVertices().size());
136         visit(g.getEntry(), visited, g);
137 
138         List<MetadataGraphVertex> dropList = new ArrayList<>(g.getVertices().size());
139 
140         // collect drop list
141         for (MetadataGraphVertex v : g.getVertices()) {
142             if (!visited.contains(v)) {
143                 dropList.add(v);
144             }
145         }
146 
147         if (dropList.size() < 1) {
148             return g;
149         }
150 
151         // now - drop vertices
152         TreeSet<MetadataGraphVertex> vertices = g.getVertices();
153         for (MetadataGraphVertex v : dropList) {
154             vertices.remove(v);
155         }
156 
157         return g;
158     }
159 
160     // -------------------------------------------------------------------------------------
161     private void visit(MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph) {
162         if (visited.contains(from)) {
163             return;
164         }
165 
166         visited.add(from);
167 
168         List<MetadataGraphEdge> exitList = graph.getExcidentEdges(from);
169         // String s = "|---> "+from.getMd().toString()+" - "+(exitList == null ? -1 : exitList.size()) + " exit links";
170         if (exitList != null && exitList.size() > 0) {
171             for (MetadataGraphEdge e : graph.getExcidentEdges(from)) {
172                 visit(e.getTarget(), visited, graph);
173             }
174         }
175     }
176 
177     // -------------------------------------------------------------------------------------
178     private MetadataGraphEdge cleanEdges(
179             MetadataGraphVertex v, List<MetadataGraphEdge> edges, ArtifactScopeEnum scope) {
180         if (edges == null || edges.isEmpty()) {
181             return null;
182         }
183 
184         if (edges.size() == 1) {
185             MetadataGraphEdge e = edges.get(0);
186             if (scope.encloses(e.getScope())) {
187                 return e;
188             }
189 
190             return null;
191         }
192 
193         MetadataGraphEdge res = null;
194 
195         for (MetadataGraphEdge e : edges) {
196             if (!scope.encloses(e.getScope())) {
197                 continue;
198             }
199 
200             if (res == null) {
201                 res = e;
202             } else {
203                 res = policy.apply(e, res);
204             }
205         }
206 
207         return res;
208     }
209     // -------------------------------------------------------------------------------------
210     // -------------------------------------------------------------------------------------
211 }