1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cling.invoker.mvnup.goals;
20
21 import java.io.IOException;
22 import java.nio.file.DirectoryStream;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.jdom2.Document;
30 import org.jdom2.Element;
31 import org.jdom2.JDOMException;
32 import org.jdom2.Namespace;
33 import org.jdom2.input.SAXBuilder;
34
35 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.Files.POM_XML;
36 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.ModelVersions.MODEL_VERSION_4_0_0;
37 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.ModelVersions.MODEL_VERSION_4_1_0;
38 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.MODEL_VERSION;
39 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.MODULE;
40 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.MODULES;
41 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.PROFILE;
42 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.PROFILES;
43 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.SUBPROJECT;
44 import static org.apache.maven.cling.invoker.mvnup.goals.UpgradeConstants.XmlElements.SUBPROJECTS;
45
46
47
48
49 public class PomDiscovery {
50
51
52
53
54
55
56
57
58
59 public static Map<Path, Document> discoverPoms(Path startDirectory) throws IOException, JDOMException {
60 Map<Path, Document> pomMap = new HashMap<>();
61
62
63 Path rootPomPath = startDirectory.resolve(POM_XML);
64 if (!Files.exists(rootPomPath)) {
65 throw new IOException("No pom.xml found in directory: " + startDirectory);
66 }
67
68 Document rootPom = loadPom(rootPomPath);
69 pomMap.put(rootPomPath, rootPom);
70
71
72 discoverModules(startDirectory, rootPom, pomMap);
73
74 return pomMap;
75 }
76
77
78
79
80
81
82
83
84
85
86
87 private static void discoverModules(Path currentDirectory, Document pomDocument, Map<Path, Document> pomMap)
88 throws IOException, JDOMException {
89
90 Element root = pomDocument.getRootElement();
91 Namespace namespace = root.getNamespace();
92
93
94 String modelVersion = detectModelVersion(pomDocument);
95 boolean is410OrLater = MODEL_VERSION_4_1_0.equals(modelVersion) || isNewerThan410(modelVersion);
96
97 boolean foundModulesOrSubprojects = false;
98
99
100 foundModulesOrSubprojects |= discoverFromModules(currentDirectory, root, namespace, pomMap);
101
102
103 if (is410OrLater) {
104 foundModulesOrSubprojects |= discoverFromSubprojects(currentDirectory, root, namespace, pomMap);
105 }
106
107
108 foundModulesOrSubprojects |= discoverFromProfiles(currentDirectory, root, namespace, pomMap, is410OrLater);
109
110
111 if (is410OrLater && !foundModulesOrSubprojects) {
112 discoverFromDirectories(currentDirectory, pomMap);
113 }
114 }
115
116
117
118
119
120 private static String detectModelVersion(Document pomDocument) {
121 Element root = pomDocument.getRootElement();
122 Namespace namespace = root.getNamespace();
123
124 String explicitVersion = null;
125 String namespaceVersion = null;
126
127
128 Element modelVersionElement = root.getChild(MODEL_VERSION, namespace);
129 if (modelVersionElement != null) {
130 explicitVersion = modelVersionElement.getTextTrim();
131 }
132
133
134 if (namespace != null && namespace.getURI() != null) {
135 String namespaceUri = namespace.getURI();
136 if (namespaceUri.contains(MODEL_VERSION_4_1_0)) {
137 namespaceVersion = MODEL_VERSION_4_1_0;
138 }
139 }
140
141
142 if (explicitVersion != null && !explicitVersion.isEmpty()) {
143
144 if (namespaceVersion != null && !explicitVersion.equals(namespaceVersion)) {
145 System.err.println("WARNING: Model version mismatch in POM - explicit: " + explicitVersion
146 + ", namespace suggests: " + namespaceVersion + ". Using explicit version.");
147 }
148 return explicitVersion;
149 }
150
151
152 if (namespaceVersion != null) {
153 return namespaceVersion;
154 }
155
156
157 System.err.println("WARNING: No model version found in POM, falling back to 4.0.0");
158 return MODEL_VERSION_4_0_0;
159 }
160
161
162
163
164 private static boolean isNewerThan410(String modelVersion) {
165
166 return modelVersion.compareTo("4.1.0") > 0;
167 }
168
169
170
171
172 private static boolean discoverFromModules(
173 Path currentDirectory, Element root, Namespace namespace, Map<Path, Document> pomMap)
174 throws IOException, JDOMException {
175 Element modulesElement = root.getChild(MODULES, namespace);
176 if (modulesElement != null) {
177 List<Element> moduleElements = modulesElement.getChildren(MODULE, namespace);
178
179 for (Element moduleElement : moduleElements) {
180 String modulePath = moduleElement.getTextTrim();
181 if (!modulePath.isEmpty()) {
182 discoverModule(currentDirectory, modulePath, pomMap);
183 }
184 }
185 return !moduleElements.isEmpty();
186 }
187 return false;
188 }
189
190
191
192
193 private static boolean discoverFromSubprojects(
194 Path currentDirectory, Element root, Namespace namespace, Map<Path, Document> pomMap)
195 throws IOException, JDOMException {
196 Element subprojectsElement = root.getChild(SUBPROJECTS, namespace);
197 if (subprojectsElement != null) {
198 List<Element> subprojectElements = subprojectsElement.getChildren(SUBPROJECT, namespace);
199
200 for (Element subprojectElement : subprojectElements) {
201 String subprojectPath = subprojectElement.getTextTrim();
202 if (!subprojectPath.isEmpty()) {
203 discoverModule(currentDirectory, subprojectPath, pomMap);
204 }
205 }
206 return !subprojectElements.isEmpty();
207 }
208 return false;
209 }
210
211
212
213
214 private static boolean discoverFromProfiles(
215 Path currentDirectory, Element root, Namespace namespace, Map<Path, Document> pomMap, boolean is410OrLater)
216 throws IOException, JDOMException {
217 boolean foundAny = false;
218 Element profilesElement = root.getChild(PROFILES, namespace);
219 if (profilesElement != null) {
220 List<Element> profileElements = profilesElement.getChildren(PROFILE, namespace);
221
222 for (Element profileElement : profileElements) {
223
224 foundAny |= discoverFromModules(currentDirectory, profileElement, namespace, pomMap);
225
226
227 if (is410OrLater) {
228 foundAny |= discoverFromSubprojects(currentDirectory, profileElement, namespace, pomMap);
229 }
230 }
231 }
232 return foundAny;
233 }
234
235
236
237
238 private static void discoverFromDirectories(Path currentDirectory, Map<Path, Document> pomMap)
239 throws IOException, JDOMException {
240 try (DirectoryStream<Path> stream = Files.newDirectoryStream(currentDirectory, Files::isDirectory)) {
241 for (Path childDir : stream) {
242 Path childPomPath = childDir.resolve(POM_XML);
243 if (Files.exists(childPomPath) && !pomMap.containsKey(childPomPath)) {
244 Document childPom = loadPom(childPomPath);
245 pomMap.put(childPomPath, childPom);
246
247
248 discoverModules(childDir, childPom, pomMap);
249 }
250 }
251 }
252 }
253
254
255
256
257
258 private static void discoverModule(Path currentDirectory, String modulePath, Map<Path, Document> pomMap)
259 throws IOException, JDOMException {
260 Path resolvedPath = currentDirectory.resolve(modulePath);
261 Path modulePomPath;
262 Path moduleDirectory;
263
264
265 if (modulePath.endsWith(POM_XML) || (Files.exists(resolvedPath) && Files.isRegularFile(resolvedPath))) {
266 modulePomPath = resolvedPath;
267 moduleDirectory = resolvedPath.getParent();
268 } else {
269
270 moduleDirectory = resolvedPath;
271 modulePomPath = moduleDirectory.resolve(POM_XML);
272 }
273
274 if (Files.exists(modulePomPath) && !pomMap.containsKey(modulePomPath)) {
275 Document modulePom = loadPom(modulePomPath);
276 pomMap.put(modulePomPath, modulePom);
277
278
279 discoverModules(moduleDirectory, modulePom, pomMap);
280 }
281 }
282
283
284
285
286
287
288
289
290
291 private static Document loadPom(Path pomPath) throws IOException, JDOMException {
292 SAXBuilder builder = new SAXBuilder();
293 return builder.build(pomPath.toFile());
294 }
295 }