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