| package aQute.bnd.maven; |
| |
| import java.io.*; |
| import java.util.*; |
| |
| import javax.xml.parsers.*; |
| import javax.xml.xpath.*; |
| |
| import org.w3c.dom.*; |
| |
| import aQute.bnd.osgi.*; |
| import aQute.lib.io.*; |
| |
| /** |
| * Provides a way to parse a maven pom as properties. This provides most of the |
| * maven elements as properties. It also provides |
| * pom.scope.[compile|test|runtime|provided|system] properties that can be |
| * appended to the build and run path. That is, they are in the correct format |
| * for this. |
| */ |
| public class PomParser extends Processor { |
| static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| static XPathFactory xpathf = XPathFactory.newInstance(); |
| static Set<String> multiple = new HashSet<String>(); |
| static Set<String> skip = new HashSet<String>(); |
| |
| static { |
| dbf.setNamespaceAware(false); |
| |
| // Set all elements that need enumeration of their elements |
| // these will not use the name of the subelement but instead |
| // they use an index from 0..n |
| multiple.add("mailingLists"); |
| multiple.add("pluginRepositories"); |
| multiple.add("repositories"); |
| multiple.add("resources"); |
| multiple.add("executions"); |
| multiple.add("goals"); |
| multiple.add("includes"); |
| multiple.add("excludes"); |
| |
| // These properties are not very useful and |
| // pollute the property space. |
| skip.add("plugins"); |
| skip.add("dependencies"); |
| skip.add("reporting"); |
| skip.add("extensions"); |
| |
| } |
| |
| public Properties getProperties(File pom) throws Exception { |
| DocumentBuilder db = dbf.newDocumentBuilder(); |
| XPath xpath = xpathf.newXPath(); |
| pom = pom.getAbsoluteFile(); |
| Document doc = db.parse(pom); |
| Properties p = new Properties(); |
| |
| // Check if there is a parent pom |
| String relativePath = xpath.evaluate("project/parent/relativePath", doc); |
| if (relativePath != null && relativePath.length() != 0) { |
| File parentPom = IO.getFile(pom.getParentFile(), relativePath); |
| if (parentPom.isFile()) { |
| Properties parentProps = getProperties(parentPom); |
| p.putAll(parentProps); |
| } else { |
| error("Parent pom for %s is not an existing file (could be directory): %s", pom, parentPom); |
| } |
| } |
| |
| Element e = doc.getDocumentElement(); |
| traverse("pom", e, p); |
| |
| String scopes[] = { |
| "provided", "runtime", "test", "system" |
| }; |
| NodeList set = (NodeList) xpath.evaluate("//dependency[not(scope) or scope='compile']", doc, |
| XPathConstants.NODESET); |
| if (set.getLength() != 0) |
| p.put("pom.scope.compile", toBsn(set)); |
| |
| for (String scope : scopes) { |
| set = (NodeList) xpath.evaluate("//dependency[scope='" + scope + "']", doc, XPathConstants.NODESET); |
| if (set.getLength() != 0) |
| p.put("pom.scope." + scope, toBsn(set)); |
| } |
| |
| return p; |
| } |
| |
| private Object toBsn(NodeList set) throws XPathExpressionException { |
| XPath xpath = xpathf.newXPath(); |
| StringBuilder sb = new StringBuilder(); |
| String del = ""; |
| for (int i = 0; i < set.getLength(); i++) { |
| Node child = set.item(i); |
| String version = xpath.evaluate("version", child); |
| sb.append(del); |
| sb.append(xpath.evaluate("groupId", child)); |
| sb.append("."); |
| sb.append(xpath.evaluate("artifactId", child)); |
| if (version != null && version.trim().length() != 0) { |
| sb.append(";version="); |
| sb.append(Analyzer.cleanupVersion(version)); |
| } |
| del = ", "; |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * The maven POM is quite straightforward, it is basically a structured |
| * property file. |
| * |
| * @param name |
| * @param parent |
| * @param p |
| */ |
| static void traverse(String name, Node parent, Properties p) { |
| if (skip.contains(parent.getNodeName())) |
| return; |
| |
| NodeList children = parent.getChildNodes(); |
| if (multiple.contains(parent.getNodeName())) { |
| int n = 0; |
| for (int i = 0; i < children.getLength(); i++) { |
| Node child = children.item(i); |
| if (!(child instanceof Text)) { |
| |
| traverse(name + "." + n++, child, p); |
| } |
| } |
| } else { |
| for (int i = 0; i < children.getLength(); i++) { |
| Node child = children.item(i); |
| if (child instanceof Text) { |
| String value = child.getNodeValue().trim(); |
| if (value.length() != 0) { |
| p.put(name, value); |
| } |
| } else { |
| traverse(name + "." + child.getNodeName(), child, p); |
| } |
| } |
| } |
| } |
| } |