/** * 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 org.eclipse.recommenders.coordinates.Coordinates.tryNewProjectCoordinate; import static org.eclipse.recommenders.coordinates.DependencyType.JAR; import static org.eclipse.recommenders.utils.Versions.canonicalizeVersion; import static org.eclipse.recommenders.utils.Zips.closeQuietly; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Properties; import java.util.jar.JarEntry; import java.util.jar.JarFile; 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.eclipse.recommenders.utils.IOUtils; import org.eclipse.recommenders.utils.Zips.DefaultJarFileConverter; import org.eclipse.recommenders.utils.Zips.IFileToJarFileConverter; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterators; /** * Implementation based on {@link MavenPomJarIdExtractor}. */ public class MavenPomPropertiesAdvisor extends AbstractProjectCoordinateAdvisor { public static final String GROUP_ID = "groupId"; public static final String ARTIFACT_ID = "artifactId"; public static final String VERSION = "version"; private static final String POM_PROPERTIES_FILE_REGEX = "META-INF/maven/.*/.*/pom.properties"; private final IFileToJarFileConverter jarFileConverter; public MavenPomPropertiesAdvisor() { jarFileConverter = new DefaultJarFileConverter(); } @VisibleForTesting MavenPomPropertiesAdvisor(IFileToJarFileConverter fileToJarFileConverter) { jarFileConverter = fileToJarFileConverter; } @Override protected Optional<ProjectCoordinate> doSuggest(DependencyInfo dependencyInfo) { JarFile jarFile = readJarFileIn(dependencyInfo.getFile()).orNull(); if (jarFile == null) { return absent(); } try { return extractProjectCoordinateOfJarFile(jarFile); } catch (IOException e) { return absent(); } finally { closeQuietly(jarFile); } } private Optional<ProjectCoordinate> extractProjectCoordinateOfJarFile(JarFile jarFile) throws IOException { Optional<ProjectCoordinate> candidate = absent(); Iterator<JarEntry> entries = pomPropertiesIterator(jarFile); while (entries.hasNext()) { JarEntry entry = entries.next(); InputStream pomProperties = jarFile.getInputStream(entry); Optional<ProjectCoordinate> projectCoordinate = parseProjectCoordinate(pomProperties, entry.getName()); IOUtils.closeQuietly(pomProperties); if (projectCoordinate.isPresent() && candidate.isPresent()) { return absent(); // We have conflicting project coordinates; abort. } candidate = candidate.or(projectCoordinate); } return candidate; } private Optional<ProjectCoordinate> parseProjectCoordinate(InputStream inputStream, String propertiesFileName) { final Properties properties = new Properties(); try { properties.load(inputStream); String groupId = properties.getProperty(GROUP_ID); String artifactId = properties.getProperty(ARTIFACT_ID); String version = properties.getProperty(VERSION); if (!extractGroupID(propertiesFileName).equals(groupId)) { return absent(); } if (!extractArtifactID(propertiesFileName).equals(artifactId)) { return absent(); } if (version == null) { return absent(); } return tryNewProjectCoordinate(groupId, artifactId, canonicalizeVersion(version)); } catch (IOException e) { return absent(); } } private Iterator<JarEntry> pomPropertiesIterator(JarFile jarFile) { return Iterators.filter(Iterators.forEnumeration(jarFile.entries()), new Predicate<JarEntry>() { @Override public boolean apply(JarEntry entry) { return entry.getName().matches(POM_PROPERTIES_FILE_REGEX); } }); } private Optional<JarFile> readJarFileIn(File file) { return jarFileConverter.createJarFile(file); } @Override public boolean isApplicable(DependencyType dependencyType) { return dependencyType == JAR; } public static String extractGroupID(String fileName) { return extract(fileName, 3); } public static String extractArtifactID(String fileName) { return extract(fileName, 2); } public static String extract(String fileName, int index) { String[] split = fileName.split("/"); if (split.length >= 4) { return split[split.length - index]; } return ""; } }