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