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 }