/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Olav Lenz - initial API and implementation */ package org.eclipse.recommenders.coordinates.maven; import static com.google.common.base.Optional.absent; import static com.google.common.base.Strings.isNullOrEmpty; import static org.eclipse.recommenders.coordinates.Coordinates.tryNewProjectCoordinate; import static org.eclipse.recommenders.coordinates.DependencyType.PROJECT; import static org.eclipse.recommenders.utils.IOUtils.closeQuietly; import static org.eclipse.recommenders.utils.Versions.canonicalizeVersion; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.eclipse.recommenders.coordinates.AbstractProjectCoordinateAdvisor; import org.eclipse.recommenders.coordinates.DependencyInfo; import org.eclipse.recommenders.coordinates.DependencyType; import org.eclipse.recommenders.coordinates.ProjectCoordinate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.google.common.base.Optional; public class MavenPomXmlAdvisor extends AbstractProjectCoordinateAdvisor { private Logger log = LoggerFactory.getLogger(MavenPomXmlAdvisor.class); @Override protected Optional<ProjectCoordinate> doSuggest(DependencyInfo dependencyInfo) { try { File pomfile = new File(dependencyInfo.getFile(), "pom.xml"); if (!pomfile.exists()) { return absent(); } else { Document model = readModelFromFile(pomfile); return extractProjectCoordinateFromModel(model); } } catch (IOException | ParserConfigurationException | SAXException | XPathExpressionException e) { log.error("Could not read pom.xml file of dependency :" + dependencyInfo, e); return absent(); } } private Document readModelFromFile(File pomfile) throws IOException, ParserConfigurationException, SAXException { InputStream pomInputStream = null; try { pomInputStream = new FileInputStream(pomfile); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBldr = docBuilderFactory.newDocumentBuilder(); return docBldr.parse(pomInputStream); } finally { closeQuietly(pomInputStream); } } private Optional<ProjectCoordinate> extractProjectCoordinateFromModel(Document model) throws XPathExpressionException { XPathFactory factory; try { factory = XPathFactory.newInstance(); } catch (RuntimeException e) { // XPathFactory.newInstance() may fail. See <https://bugs.eclipse.org/bugs/show_bug.cgi?id=477141> log.error("Could not create XPathFactory. Try running Eclipse with -Djaxp.debug=true", e); return absent(); } String groupId = factory.newXPath().evaluate("/project/groupId/text()", model); String artifactId = factory.newXPath().evaluate("/project/artifactId/text()", model); String version = factory.newXPath().evaluate("/project/version/text()", model); if (isNullOrEmpty(groupId)) { groupId = factory.newXPath().evaluate("/project/parent/groupId/text()", model); } if (isNullOrEmpty(version)) { version = factory.newXPath().evaluate("/project/parent/version/text()", model); } if (isNullOrEmpty(groupId) || isNullOrEmpty(artifactId) || isNullOrEmpty(version)) { return absent(); } if (containsPropertyReference(groupId) || containsPropertyReference(artifactId) || containsPropertyReference(version)) { return absent(); } int indexOf = version.indexOf('-'); version = version.substring(0, indexOf == -1 ? version.length() : indexOf); return tryNewProjectCoordinate(groupId, artifactId, canonicalizeVersion(version)); } private boolean containsPropertyReference(String string) { return string.contains("$"); } @Override public boolean isApplicable(DependencyType type) { return PROJECT == type; } }