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 }