blob: e529141ddb6abaee4e2f725da8bd302d9b752474 [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.bnd.maven;
2
3import java.io.*;
4import java.util.*;
5
6import javax.xml.parsers.*;
7import javax.xml.xpath.*;
8
9import org.w3c.dom.*;
10
11import aQute.lib.io.*;
12import aQute.lib.osgi.*;
13
14/**
15 * Provides a way to parse a maven pom as properties.
16 *
17 * This provides most of the maven elements as properties. It also
18 * provides pom.scope.[compile|test|runtime|provided|system] properties
19 * that can be appended to the build and run path. That is, they are
20 * in the correct format for this.
21 */
22public class PomParser extends Processor {
23 static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
24 static XPathFactory xpathf = XPathFactory.newInstance();
25 static Set<String> multiple = new HashSet<String>();
26 static Set<String> skip = new HashSet<String>();
27
28 static {
29 dbf.setNamespaceAware(false);
30
31 // Set all elements that need enumeration of their elements
32 // these will not use the name of the subelement but instead
33 // they use an index from 0..n
34 multiple.add("mailingLists");
35 multiple.add("pluginRepositories");
36 multiple.add("repositories");
37 multiple.add("resources");
38 multiple.add("executions");
39 multiple.add("goals");
40 multiple.add("includes");
41 multiple.add("excludes");
42
43 // These properties are not very useful and
44 // pollute the property space.
45 skip.add("plugins");
46 skip.add("dependencies");
47 skip.add("reporting");
48 skip.add("extensions");
49
50 }
51
52 public Properties getProperties(File pom) throws Exception {
53 DocumentBuilder db = dbf.newDocumentBuilder();
54 XPath xpath = xpathf.newXPath();
55 pom = pom.getAbsoluteFile();
56 Document doc = db.parse(pom);
57 Properties p = new Properties();
58
59 // Check if there is a parent pom
60 String relativePath = xpath.evaluate("project/parent/relativePath", doc);
61 if (relativePath != null && relativePath.length()!=0) {
62 File parentPom = IO.getFile(pom.getParentFile(), relativePath);
63 if (parentPom.isFile()) {
64 Properties parentProps = getProperties(parentPom);
65 p.putAll(parentProps);
66 } else {
67 error("Parent pom for %s is not an existing file (could be directory): %s", pom, parentPom);
68 }
69 }
70
71 Element e = doc.getDocumentElement();
72 traverse("pom", e, p);
73
74 String scopes[] = { "provided", "runtime", "test", "system" };
75 NodeList set = (NodeList) xpath.evaluate("//dependency[not(scope) or scope='compile']", doc,
76 XPathConstants.NODESET);
77 if (set.getLength() != 0)
78 p.put("pom.scope.compile", toBsn(set));
79
80 for (String scope : scopes) {
81 set = (NodeList) xpath.evaluate("//dependency[scope='" + scope + "']", doc,
82 XPathConstants.NODESET);
83 if (set.getLength() != 0)
84 p.put("pom.scope." + scope, toBsn(set));
85 }
86
87 return p;
88 }
89
90 private Object toBsn(NodeList set) throws XPathExpressionException {
91 XPath xpath = xpathf.newXPath();
92 StringBuilder sb = new StringBuilder();
93 String del = "";
94 for (int i = 0; i < set.getLength(); i++) {
95 Node child = set.item(i);
96 String version = xpath.evaluate("version", child);
97 sb.append(del);
98 sb.append(xpath.evaluate("groupId", child));
99 sb.append(".");
100 sb.append(xpath.evaluate("artifactId", child));
101 if (version != null && version.trim().length()!=0) {
102 sb.append(";version=");
103 sb.append( Analyzer.cleanupVersion(version));
104 }
105 del = ", ";
106 }
107 return sb.toString();
108 }
109
110 /**
111 * The maven POM is quite straightforward, it is basically a structured property file.
112 * @param name
113 * @param parent
114 * @param p
115 */
116 static void traverse(String name, Node parent, Properties p) {
117 if ( skip.contains(parent.getNodeName()))
118 return;
119
120 NodeList children = parent.getChildNodes();
121 if (multiple.contains(parent.getNodeName())) {
122 int n = 0;
123 for (int i = 0; i < children.getLength(); i++) {
124 Node child = children.item(i);
125 if (!(child instanceof Text)) {
126
127 traverse(name + "." + n++, child, p);
128 }
129 }
130 } else {
131 for (int i = 0; i < children.getLength(); i++) {
132 Node child = children.item(i);
133 if (child instanceof Text) {
134 String value = child.getNodeValue().trim();
135 if (value.length()!=0) {
136 p.put(name, value);
137 }
138 } else {
139 traverse(name + "." + child.getNodeName(), child, p);
140 }
141 }
142 }
143 }
144}