1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package io.github.tonywasher.joceanus.themis.parser.maven;
19
20 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
21 import io.github.tonywasher.joceanus.themis.exc.ThemisDataException;
22 import io.github.tonywasher.joceanus.themis.exc.ThemisIOException;
23 import io.github.tonywasher.joceanus.themis.parser.base.ThemisChar;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Element;
26 import org.w3c.dom.Node;
27 import org.xml.sax.SAXException;
28
29 import javax.xml.XMLConstants;
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33 import javax.xml.xpath.XPath;
34 import javax.xml.xpath.XPathConstants;
35 import javax.xml.xpath.XPathExpressionException;
36 import javax.xml.xpath.XPathFactory;
37 import java.io.BufferedInputStream;
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.IOException;
41 import java.io.InputStream;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Objects;
45
46
47
48
49 public class ThemisMavenPomParser {
50
51
52
53 private static final String DOC_NAME = "project";
54
55
56
57
58 private static final String PARENT_NAME = "parent";
59
60
61
62
63 private static final String GROUP_NAME = "groupId";
64
65
66
67
68 private static final String VERSION_NAME = "version";
69
70
71
72
73 private static final String DOC_PREFIX = "/" + DOC_NAME;
74
75
76
77
78 private static final String XPATH_PROPERTIES = DOC_PREFIX + "/properties";
79
80
81
82
83 private static final String XPATH_PARENT = DOC_PREFIX + ThemisChar.COMMENT + PARENT_NAME;
84
85
86
87
88 private static final String XPATH_MODULES = DOC_PREFIX + "/modules";
89
90
91
92
93 private static final String XPATH_DEPENDENCYMGMT = DOC_PREFIX + "/dependencyManagement/dependencies";
94
95
96
97
98 private static final String XPATH_DEPENDENCIES = DOC_PREFIX + "/dependencies";
99
100
101
102
103 private static final String XPATH_PACKAGING = DOC_PREFIX + "/packaging";
104
105
106
107
108 private static final String XPATH_XTRADIRS = DOC_PREFIX
109 + "/build/plugins/plugin[artifactId='build-helper-maven-plugin']"
110 + "/executions/execution/configuration/sources";
111
112
113
114
115 private static final String EL_MODULE = "module";
116
117
118
119
120 private static final String EL_DEPENDENCY = "dependency";
121
122
123
124
125 private static final String EL_SOURCE = "source";
126
127
128
129
130 private static final String PARENT_GROUP = PARENT_NAME + ThemisChar.PERIOD + DOC_NAME + ThemisChar.PERIOD + GROUP_NAME;
131
132
133
134
135 private static final String PARENT_VERSION = PARENT_NAME + ThemisChar.PERIOD + DOC_NAME + ThemisChar.PERIOD + VERSION_NAME;
136
137
138
139
140 private static final String PROJECT_GROUP = DOC_NAME + ThemisChar.PERIOD + GROUP_NAME;
141
142
143
144
145 private static final String PROJECT_VERSION = DOC_NAME + ThemisChar.PERIOD + VERSION_NAME;
146
147
148
149
150 private final Document theDoc;
151
152
153
154
155 private final XPath theXPath;
156
157
158
159
160 private ThemisMavenPropertyCache theProperties;
161
162
163
164
165
166
167
168
169 public ThemisMavenPomParser(final File pLocation,
170 final ThemisMavenPropertyCache pProperties) throws OceanusException {
171
172 theProperties = pProperties;
173
174
175 try (InputStream myInputStream = new FileInputStream(pLocation);
176 BufferedInputStream myInBuffer = new BufferedInputStream(myInputStream)) {
177 final DocumentBuilderFactory myFactory = DocumentBuilderFactory.newInstance();
178 myFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
179 myFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
180 myFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
181 final DocumentBuilder myBuilder = myFactory.newDocumentBuilder();
182
183
184 theXPath = XPathFactory.newInstance().newXPath();
185
186
187 theDoc = myBuilder.parse(myInBuffer);
188
189
190 final Element myDoc = theDoc.getDocumentElement();
191
192
193 if (!Objects.equals(myDoc.getNodeName(), DOC_NAME)) {
194 throw new ThemisDataException("Invalid document type");
195 }
196
197
198 } catch (IOException
199 | ParserConfigurationException
200 | SAXException e) {
201 throw new ThemisIOException("Exception accessing Pom file", e);
202 }
203 }
204
205
206
207
208
209
210 void readProperties() throws OceanusException {
211
212 final Node myProps = findNode(XPATH_PROPERTIES);
213 if (myProps != null) {
214 for (Node myNode = myProps.getFirstChild(); myNode != null; myNode = myNode.getNextSibling()) {
215 if (myNode instanceof Element myElement) {
216 theProperties.setProperty(myElement.getNodeName(),
217 myElement.getTextContent());
218 }
219 }
220 }
221 }
222
223
224
225
226
227
228
229 boolean isJarPackaging() throws OceanusException {
230
231 final Element myPackageEl = (Element) findNode(XPATH_PACKAGING);
232 return myPackageEl == null
233 || "jar".equals(myPackageEl.getTextContent())
234 || "bundle".equals(myPackageEl.getTextContent());
235 }
236
237
238
239
240
241
242
243 ThemisMavenId getParent() throws OceanusException {
244
245 final Element myParentEl = (Element) findNode(XPATH_PARENT);
246 final ThemisMavenId myParent = myParentEl == null
247 ? null
248 : new ThemisMavenId(theProperties, myParentEl);
249
250
251 if (myParent != null) {
252 storeParentProperties(myParent);
253 }
254
255
256 return myParent;
257 }
258
259
260
261
262
263
264 private void storeParentProperties(final ThemisMavenId pParent) {
265
266 theProperties.setProperty(PARENT_GROUP, pParent.getGroupId());
267 theProperties.setProperty(PARENT_VERSION, pParent.getVersion());
268 }
269
270
271
272
273
274
275
276
277 ThemisMavenId getId(final ThemisMavenId pParent) throws OceanusException {
278
279 final ThemisMavenId myProject = new ThemisMavenId(theProperties, theDoc.getDocumentElement(), pParent);
280
281
282 storeSelfProperties(myProject);
283
284
285 return myProject;
286 }
287
288
289
290
291
292
293 private void storeSelfProperties(final ThemisMavenId pProject) {
294
295 String myGroupId = pProject.getGroupId();
296 myGroupId = myGroupId != null ? myGroupId : theProperties.getProperty(PARENT_GROUP);
297
298
299 String myVersion = pProject.getVersion();
300 myVersion = myVersion != null ? myVersion : theProperties.getProperty(PARENT_VERSION);
301
302
303 theProperties.setProperty(PROJECT_GROUP, myGroupId);
304 theProperties.setProperty(PROJECT_VERSION, myVersion);
305 }
306
307
308
309
310
311
312
313 List<String> getModules() throws OceanusException {
314
315 final List<String> myList = new ArrayList<>();
316 final Node myModules = findNode(XPATH_MODULES);
317 if (myModules != null) {
318
319 for (Node myChild = myModules.getFirstChild();
320 myChild != null;
321 myChild = myChild.getNextSibling()) {
322
323 if (myChild instanceof Element
324 && EL_MODULE.equals(myChild.getNodeName())) {
325 myList.add(myChild.getTextContent());
326 }
327 }
328 }
329
330
331 return myList;
332 }
333
334
335
336
337
338
339
340 List<ThemisMavenId> getDependencyManagement() throws OceanusException {
341 return getDependencies(XPATH_DEPENDENCYMGMT);
342 }
343
344
345
346
347
348
349
350 List<ThemisMavenId> getDependencies() throws OceanusException {
351 return getDependencies(XPATH_DEPENDENCIES);
352 }
353
354
355
356
357
358
359
360
361 private List<ThemisMavenId> getDependencies(final String pPath) throws OceanusException {
362
363 final List<ThemisMavenId> myList = new ArrayList<>();
364 final Node myDependencies = findNode(pPath);
365 if (myDependencies != null) {
366
367 for (Node myChild = myDependencies.getFirstChild();
368 myChild != null;
369 myChild = myChild.getNextSibling()) {
370
371 if (myChild instanceof Element myElement
372 && EL_DEPENDENCY.equals(myChild.getNodeName())) {
373 final ThemisMavenId myId = new ThemisMavenId(theProperties, myElement);
374 if (!myId.isSkippable()) {
375 myList.add(myId);
376 }
377 }
378 }
379 }
380
381
382 return myList;
383 }
384
385
386
387
388
389
390
391 List<String> getXtraDirs() throws OceanusException {
392
393 final List<String> myList = new ArrayList<>();
394 final Node myXtraDirs = findNode(XPATH_XTRADIRS);
395 if (myXtraDirs != null) {
396
397 for (Node myChild = myXtraDirs.getFirstChild();
398 myChild != null;
399 myChild = myChild.getNextSibling()) {
400
401 if (myChild instanceof Element
402 && EL_SOURCE.equals(myChild.getNodeName())) {
403 myList.add(myChild.getTextContent());
404 }
405 }
406 }
407
408
409 return myList;
410 }
411
412
413
414
415
416
417
418
419 private Node findNode(final String pPath) throws OceanusException {
420
421 try {
422 return (Node) theXPath.compile(pPath).evaluate(theDoc, XPathConstants.NODE);
423 } catch (XPathExpressionException e) {
424 throw new ThemisDataException("Exception locating XPath: " + pPath, e);
425 }
426 }
427 }