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 java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  import org.apache.maven.artifact.ArtifactScopeEnum;
25  import org.codehaus.plexus.component.annotations.Component;
26  import org.codehaus.plexus.component.annotations.Requirement;
27  
28  /**
29   * default implementation of the metadata classpath transformer
30   *
31   * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
32   *
33   */
34  @Component(role = ClasspathTransformation.class)
35  public class DefaultClasspathTransformation implements ClasspathTransformation {
36      @Requirement
37      GraphConflictResolver conflictResolver;
38  
39      // ----------------------------------------------------------------------------------------------------
40      public ClasspathContainer transform(MetadataGraph dirtyGraph, ArtifactScopeEnum scope, boolean resolve)
41              throws MetadataGraphTransformationException {
42          try {
43              if (dirtyGraph == null || dirtyGraph.isEmpty()) {
44                  return null;
45              }
46  
47              MetadataGraph cleanGraph = conflictResolver.resolveConflicts(dirtyGraph, scope);
48  
49              if (cleanGraph == null || cleanGraph.isEmpty()) {
50                  return null;
51              }
52  
53              ClasspathContainer cpc = new ClasspathContainer(scope);
54              if (cleanGraph.isEmptyEdges()) {
55                  // single entry in the classpath, populated from itself
56                  ArtifactMetadata amd = cleanGraph.getEntry().getMd();
57                  cpc.add(amd);
58              } else {
59                  ClasspathGraphVisitor v = new ClasspathGraphVisitor(cleanGraph, cpc);
60                  MetadataGraphVertex entry = cleanGraph.getEntry();
61                  // entry point
62                  v.visit(entry);
63              }
64  
65              return cpc;
66          } catch (GraphConflictResolutionException e) {
67              throw new MetadataGraphTransformationException(e);
68          }
69      }
70  
71      // ===================================================================================================
72      /**
73       * Helper class to traverse graph. Required to make the containing method thread-safe
74       * and yet use class level data to lessen stack usage in recursion
75       */
76      private class ClasspathGraphVisitor {
77          MetadataGraph graph;
78  
79          ClasspathContainer cpc;
80  
81          List<MetadataGraphVertex> visited;
82  
83          // -----------------------------------------------------------------------
84          protected ClasspathGraphVisitor(MetadataGraph cleanGraph, ClasspathContainer cpc) {
85              this.cpc = cpc;
86              this.graph = cleanGraph;
87  
88              visited = new ArrayList<>(cleanGraph.getVertices().size());
89          }
90  
91          // -----------------------------------------------------------------------
92          protected void visit(MetadataGraphVertex node) // , String version, String artifactUri )
93                  {
94              ArtifactMetadata md = node.getMd();
95              if (visited.contains(node)) {
96                  return;
97              }
98  
99              cpc.add(md);
100             //
101             //            TreeSet<MetadataGraphEdge> deps = new TreeSet<MetadataGraphEdge>(
102             //                        new Comparator<MetadataGraphEdge>()
103             //                        {
104             //                            public int compare( MetadataGraphEdge e1
105             //                                              , MetadataGraphEdge e2
106             //                                              )
107             //                            {
108             //                                if( e1.getDepth() == e2.getDepth() )
109             //                                {
110             //                                    if( e2.getPomOrder() == e1.getPomOrder() )
111             //                                        return
112             // e1.getTarget().toString().compareTo(e2.getTarget().toString() );
113             //
114             //                                    return e2.getPomOrder() - e1.getPomOrder();
115             //                                }
116             //
117             //                                return e2.getDepth() - e1.getDepth();
118             //                            }
119             //                        }
120             //                    );
121 
122             List<MetadataGraphEdge> exits = graph.getExcidentEdges(node);
123 
124             if (exits != null && exits.size() > 0) {
125                 MetadataGraphEdge[] sortedExits = exits.toArray(new MetadataGraphEdge[0]);
126                 Arrays.sort(sortedExits, (e1, e2) -> {
127                     if (e1.getDepth() == e2.getDepth()) {
128                         if (e2.getPomOrder() == e1.getPomOrder()) {
129                             return e1.getTarget()
130                                     .toString()
131                                     .compareTo(e2.getTarget().toString());
132                         }
133                         return e2.getPomOrder() - e1.getPomOrder();
134                     }
135                     return e2.getDepth() - e1.getDepth();
136                 });
137 
138                 for (MetadataGraphEdge e : sortedExits) {
139                     MetadataGraphVertex targetNode = e.getTarget();
140                     targetNode.getMd().setArtifactScope(e.getScope());
141                     targetNode.getMd().setWhy(e.getSource().getMd().toString());
142                     visit(targetNode);
143                 }
144             }
145         }
146         // -----------------------------------------------------------------------
147         // -----------------------------------------------------------------------
148     }
149     // ----------------------------------------------------------------------------------------------------
150     // ----------------------------------------------------------------------------------------------------
151 }