/* * Copyright 2012 James Moger * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.moxie; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.moxie.Constants.Key; import org.moxie.MoxieException.MissingParentPomException; import org.moxie.utils.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class PomReader { /** * Enum to control how strictly the PomReader enforces missing or incomplete * data. */ public static enum Requirements { STRICT(true, true), LOOSE(false, false); final boolean requireParent; final boolean resolveProperties; Requirements(boolean requireParent, boolean resolveProperties) { this.requireParent = requireParent; this.resolveProperties = resolveProperties; } } /** * Reads a POM file from an artifact cache. Parent POMs will be read and * applied automatically, if they exist in the cache. * * @param cache * @param dependency * @return * @throws Exception */ public static Pom readPom(IMavenCache cache, Dependency dependency) { File pomFile = cache.getArtifact(dependency, Constants.POM); if (!pomFile.exists()) { return null; } return readPom(cache, pomFile, Requirements.STRICT); } /** * Reads a POM file from an artifact cache. Parent POMs will be read and * applied automatically, if they exist in the cache. * * @param cache * @param pomFile * @return * @throws Exception */ public static Pom readPom(IMavenCache cache, File pomFile) { return readPom(cache, pomFile, Requirements.STRICT); } /** * Reads a POM file from an artifact cache. Parent POMs will be read and * applied automatically, if they exist in the cache. * * @param cache * @param pomFile * @param requirements * @return * @throws Exception */ public static Pom readPom(IMavenCache cache, File pomFile, Requirements requirements) { Document doc = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); doc = builder.parse(pomFile); doc.getDocumentElement().normalize(); } catch (Exception e) { throw new RuntimeException(e); } Element docElement = doc.getDocumentElement(); Pom pom = new Pom(); List<Dependency> managedList = new ArrayList<Dependency>(); List<Dependency> dependencyList = new ArrayList<Dependency>(); NodeList projectNodes = docElement.getChildNodes(); for (int i = 0; i < projectNodes.getLength(); i++) { Node pNode = projectNodes.item(i); if (pNode.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) pNode; if ("parent".equalsIgnoreCase(element.getTagName())) { // parent properties pom.parentGroupId = readStringTag(pNode, Key.groupId); pom.parentArtifactId = readStringTag(pNode, Key.artifactId); pom.parentVersion = readStringTag(pNode, Key.version); // read parent pom Dependency parent = pom.getParentDependency(); Pom parentPom = readPom(cache, parent); if (parentPom == null) { // we do not have the parent POM in the cache if (requirements.requireParent) { // notify the caller of the missing POM throw new MissingParentPomException(parent); } // loose parsing option: // we do not have the parent pom yet likely because we // are in the middle of downloading so make a fake one // to satisfy ${parent.} property inheritance parentPom = new Pom(); parentPom.groupId = pom.parentGroupId; parentPom.artifactId = pom.parentArtifactId; parentPom.version = pom.parentVersion; } pom.inherit(parentPom); } else if ("properties".equalsIgnoreCase(element.getTagName())) { // pom properties NodeList properties = (NodeList) element; for (int j = 0; j < properties.getLength(); j++) { Node node = properties.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { String property = node.getNodeName(); if (node.getFirstChild() != null) { pom.setProperty(property, node.getFirstChild().getNodeValue()); } } } } else if ("dependencyManagement".equalsIgnoreCase(element.getTagName())) { // dependencyManagement definitions NodeList dependencies = element.getElementsByTagName("dependency"); for (int j = 0, jlen = dependencies.getLength(); j < jlen; j++) { Node node = dependencies.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { // dependencyManagement.dependency Dependency dep = readDependency(node); Scope scope = Scope.fromString(readStringTag(node, Key.scope)); dep.definedScope = scope; managedList.add(dep); } } } else if ("dependencies".equalsIgnoreCase(element.getTagName())) { // read dependencies NodeList dependencies = (NodeList) element; for (int j = 0; j < dependencies.getLength(); j++) { Node node = dependencies.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { // dependencies.dependency Dependency dep = readDependency(node); Scope scope = Scope.fromString(readStringTag(node, Key.scope)); if (scope == null) { scope = Scope.compile; } dep.definedScope = scope; dependencyList.add(dep); } } } else if ("licenses".equalsIgnoreCase(element.getTagName())) { // read licenses // do not inherit licenses as this pom defines them pom.clearLicenses(); NodeList licenses = (NodeList) element; for (int j = 0; j < licenses.getLength(); j++) { Node node = licenses.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { // licenses.license String name = readStringTag(node, Key.name); String url = readStringTag(node, Key.url); License license = new License(name, url); license.distribution = readStringTag(node, Key.distribution); license.comments = readStringTag(node, Key.comments); pom.addLicense(license); } } } else if ("developers".equalsIgnoreCase(element.getTagName())) { // read developers NodeList developers = (NodeList) element; for (int j = 0; j < developers.getLength(); j++) { Node node = developers.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { // developers.developer Person person = readPerson(node); pom.addDeveloper(person); } } } else if ("contributors".equalsIgnoreCase(element.getTagName())) { // read contributors NodeList contributors = (NodeList) element; for (int j = 0; j < contributors.getLength(); j++) { Node node = contributors.item(j); if (node.getNodeType() == Node.ELEMENT_NODE) { // contributors.contributor Person person = readPerson(node); pom.addContributor(person); } } } else if ("scm".equalsIgnoreCase(element.getTagName())) { // scm properties pom.scm.connection = readStringTag(pNode, Key.connection); pom.scm.developerConnection = readStringTag(pNode, Key.developerConnection); pom.scm.url = readStringTag(pNode, Key.url); pom.scm.tag = readStringTag(pNode, Key.tag); } else if ("issueManagement".equalsIgnoreCase(element.getTagName())) { // extract the issue tracker url pom.issuesUrl = readStringTag(element, Key.url); } else if ("groupId".equalsIgnoreCase(element.getTagName())) { // extract the groupId pom.groupId = readStringTag(element); } else if ("artifactId".equalsIgnoreCase(element.getTagName())) { // extract the artifactId pom.artifactId = readStringTag(element); } else if ("version".equalsIgnoreCase(element.getTagName())) { // extract the version pom.version = readStringTag(element); } else if ("packaging".equalsIgnoreCase(element.getTagName())) { // extract the packaging pom.packaging = readStringTag(element); } else if ("name".equalsIgnoreCase(element.getTagName())) { // extract the name pom.name = readStringTag(element); } else if ("description".equalsIgnoreCase(element.getTagName())) { // extract the description pom.description = readStringTag(element); } else if ("url".equalsIgnoreCase(element.getTagName())) { // extract the url pom.url = readStringTag(element); } else if ("organization".equalsIgnoreCase(element.getTagName())) { // extract the organization data pom.organization = readStringTag(element, Key.name); pom.organizationUrl = readStringTag(element, Key.url); } else if ("inceptionYear".equalsIgnoreCase(element.getTagName())) { // extract the inception year pom.inceptionYear = readStringTag(element); } } } if (requirements.resolveProperties) { pom.resolveProperties(); } // Add managed dependencies after resolving all properties for (Dependency dep : managedList) { if (Scope.imprt.equals(dep.definedScope)) { // dependencyManagement import Pom importPom = readPom(cache, dep); if (importPom != null) { pom.importManagedDependencies(importPom); } } else { // add dependency management definition pom.addManagedDependency(dep, dep.definedScope, requirements.resolveProperties); } } // Add dependencies after adding all managed dependencies for (Dependency dep : dependencyList) { Scope addedScope = pom.addDependency(dep, dep.definedScope, requirements.resolveProperties); dep.definedScope = addedScope; } return pom; } private static Dependency readDependency(Node node) { Dependency dep = new Dependency(); dep.groupId = readStringTag(node, Key.groupId); dep.artifactId = readStringTag(node, Key.artifactId); dep.version = readStringTag(node, Key.version); dep.classifier = readStringTag(node, Key.classifier); dep.type = readStringTag(node, Key.type); dep.extension = Constants.getExtension(dep.type); dep.optional = readBooleanTag(node, Key.optional); dep.exclusions.addAll(readExclusions(node)); return dep; } private static Person readPerson(Node node) { Person person = new Person(); person.id = readStringTag(node, Key.id); person.name = readStringTag(node, Key.name); person.email = readStringTag(node, Key.email); person.url = readStringTag(node, Key.url); person.organization = readStringTag(node, Key.organization); person.organizationUrl = readStringTag(node, Key.organizationUrl); person.roles = new ArrayList<String>(); NodeList roles = ((Element) node).getElementsByTagName("role"); for (int i = 0; i < roles.getLength(); i++) { person.roles.add(readStringTag(roles.item(i))); } return person; } private static String readStringTag(Node node, Key tag) { Element element = (Element) node; NodeList tagList = element.getElementsByTagName(tag.name()); if (tagList == null || tagList.getLength() == 0) { return null; } Element tagElement = (Element) tagList.item(0); NodeList textList = tagElement.getChildNodes(); Node itemNode = textList.item(0); if (itemNode == null) { return null; } String content = itemNode.getNodeValue().trim(); return content; } private static String readStringTag(Node node) { if (node == null) { return null; } Node tagElement = node.getFirstChild(); if (tagElement == null) { return null; } String content = tagElement.getTextContent(); return content; } private static boolean readBooleanTag(Node node, Key tag) { String content = readStringTag(node, tag); if (StringUtils.isEmpty(content)) { return false; } return Boolean.parseBoolean(content); } private static Collection<String> readExclusions(Node node) { Set<String> exclusions = new LinkedHashSet<String>(); Element element = (Element) node; NodeList exclusionList = element.getElementsByTagName("exclusion"); if (exclusionList == null || exclusionList.getLength() == 0) { return exclusions; } for (int i = 0; i < exclusionList.getLength(); i++) { Node exclusionNode = exclusionList.item(i); String groupId = readStringTag(exclusionNode, Key.groupId); String artifactId = readStringTag(exclusionNode, Key.artifactId); if (StringUtils.isEmpty(artifactId)) { // group exclusion exclusions.add(groupId); } else { // artifact exclusion exclusions.add(groupId + ":" + artifactId); } } return exclusions; } }