Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Fedorenko2017-11-19 23:26:34 +0000
committerIgor Fedorenko2018-05-21 13:17:14 +0000
commitb68b8b26d23c41b94abd1b02a1864ab52038f6c1 (patch)
tree0a61500c5afc9f8c56a4e65b308d5f1b81bcb3b0 /org.eclipse.m2e.sourcelookup/src
parent4c27b30f5335de0e98805a42ff83622a854daedd (diff)
downloadm2e-core-b68b8b26d23c41b94abd1b02a1864ab52038f6c1.tar.gz
m2e-core-b68b8b26d23c41b94abd1b02a1864ab52038f6c1.tar.xz
m2e-core-b68b8b26d23c41b94abd1b02a1864ab52038f6c1.zip
Bug 384065: advanced sourcelookup support
Change-Id: Ib145445c60c686bbbc187f252b32591535ac740d Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
Diffstat (limited to 'org.eclipse.m2e.sourcelookup/src')
-rw-r--r--org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenArtifactIdentifier.java160
-rw-r--r--org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceContainerResolver.java85
-rw-r--r--org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceLookupParticipant.java41
-rw-r--r--org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MetaInfMavenScanner.java90
4 files changed, 376 insertions, 0 deletions
diff --git a/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenArtifactIdentifier.java b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenArtifactIdentifier.java
new file mode 100644
index 00000000..af625b72
--- /dev/null
+++ b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenArtifactIdentifier.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 Igor Fedorenko
+ * 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:
+ * Igor Fedorenko - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2e.sourcelookup.internal.launch;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.internal.index.IIndex;
+import org.eclipse.m2e.core.internal.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.index.nexus.CompositeIndex;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.hash.Hashing;
+import com.google.common.io.Files;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+@SuppressWarnings("restriction")
+public class MavenArtifactIdentifier {
+
+ // reads META-INF/maven/**/pom.properties
+ private static final MetaInfMavenScanner<Properties> scanner = new MetaInfMavenScanner<Properties>() {
+ @Override
+ protected Properties visitFile(File file) throws IOException {
+ // TODO validate properties and path match
+ try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
+ return loadProperties(is);
+ }
+ }
+
+ @Override
+ protected Properties visitJarEntry(JarFile jar, JarEntry entry) throws IOException {
+ // TODO validate properties and path match
+ try (InputStream is = jar.getInputStream(entry)) {
+ return loadProperties(is);
+ }
+ }
+
+ private Properties loadProperties(InputStream is) throws IOException {
+ Properties properties = new Properties();
+ properties.load(is);
+ return properties;
+ }
+ };
+
+ public Collection<ArtifactKey> identify(File classesLocation, IProgressMonitor monitor) {
+ // checksum-based lookup in nexus index
+ // checksum-based lookup in central
+ // GAV extracted from pom.properties
+
+ Collection<ArtifactKey> classesArtifacts = identifyNexusIndexer(classesLocation);
+ if (classesArtifacts == null) {
+ classesArtifacts = identifyCentralSearch(classesLocation);
+ }
+ if (classesArtifacts == null) {
+ classesArtifacts = scanPomProperties(classesLocation);
+ }
+
+ return classesArtifacts;
+ }
+
+ protected Collection<ArtifactKey> identifyNexusIndexer(File file) {
+ if (!file.isFile()) {
+ return null;
+ }
+
+ try {
+ IIndex index = MavenPlugin.getIndexManager().getAllIndexes();
+
+ List<IndexedArtifactFile> identified;
+ if (index instanceof CompositeIndex) {
+ identified = ((CompositeIndex) index).identifyAll(file);
+ } else {
+ IndexedArtifactFile indexed = index.identify(file);
+ if (indexed != null) {
+ identified = Collections.singletonList(indexed);
+ } else {
+ identified = Collections.emptyList();
+ }
+ }
+
+ for (IndexedArtifactFile indexed : identified) {
+ if (indexed.sourcesExists == IIndex.PRESENT) {
+ return Collections.singleton(indexed.getArtifactKey());
+ }
+ }
+ } catch (CoreException e) {
+ // TODO maybe log, but ignore otherwise
+ }
+
+ return null;
+ }
+
+ protected Collection<ArtifactKey> identifyCentralSearch(File file) {
+ if (!file.isFile()) {
+ return null;
+ }
+
+ try {
+ String sha1 = Files.hash(file, Hashing.sha1()).toString(); // TODO use Locations for caching
+ URL url = new URL("https://search.maven.org/solrsearch/select?q=1:" + sha1);
+ try (InputStreamReader reader = new InputStreamReader(url.openStream(), Charsets.UTF_8)) {
+ Set<ArtifactKey> result = new LinkedHashSet<>();
+ JsonObject container = new Gson().fromJson(reader, JsonObject.class);
+ JsonArray docs = container.get("response").getAsJsonObject().get("docs").getAsJsonArray();
+ for (int i = 0; i < docs.size(); i++) {
+ JsonObject doc = docs.get(i).getAsJsonObject();
+ String g = doc.get("g").getAsString();
+ String a = doc.get("a").getAsString();
+ String v = doc.get("v").getAsString();
+ result.add(new ArtifactKey(g, a, v, null));
+ }
+ return !result.isEmpty() ? ImmutableSet.copyOf(result) : null;
+ }
+ } catch (IOException e) {
+ // TODO maybe log, ignore otherwise
+ }
+ return null;
+ }
+
+ public Collection<ArtifactKey> scanPomProperties(File classesLocation) {
+ Set<ArtifactKey> artifacts = new LinkedHashSet<>();
+ for (Properties pomProperties : scanner.scan(classesLocation, "pom.properties")) {
+ String groupId = pomProperties.getProperty("groupId");
+ String artifactId = pomProperties.getProperty("artifactId");
+ String version = pomProperties.getProperty("version");
+ if (groupId != null && artifactId != null && version != null) {
+ artifacts.add(new ArtifactKey(groupId, artifactId, version, /* classifier= */null));
+ }
+ }
+ return ImmutableSet.copyOf(artifacts);
+ }
+}
diff --git a/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceContainerResolver.java b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceContainerResolver.java
new file mode 100644
index 00000000..6b4a6b26
--- /dev/null
+++ b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceContainerResolver.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 Igor Fedorenko
+ * 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:
+ * Igor Fedorenko - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2e.sourcelookup.internal.launch;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.launching.sourcelookup.advanced.ISourceContainerResolver;
+import org.eclipse.jdt.launching.sourcelookup.containers.JavaProjectSourceContainer;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.IMavenProjectRegistry;
+
+
+public class MavenSourceContainerResolver implements ISourceContainerResolver {
+
+ private static final MavenArtifactIdentifier INDENTIFIER = new MavenArtifactIdentifier();
+
+ @Override
+ public Collection<ISourceContainer> resolveSourceContainers(File classesLocation, IProgressMonitor monitor) {
+ Collection<ArtifactKey> classesArtifacts = INDENTIFIER.identify(classesLocation, monitor);
+
+ if (classesArtifacts == null) {
+ return null;
+ }
+
+ List<ISourceContainer> result = new ArrayList<>();
+ for (ArtifactKey classesArtifact : classesArtifacts) {
+ ISourceContainer container = resolveSourceContainer(classesArtifact, monitor);
+ if (container != null) {
+ result.add(container);
+ }
+ }
+ return result;
+ }
+
+ protected ISourceContainer resolveSourceContainer(ArtifactKey artifact, IProgressMonitor monitor) {
+ String groupId = artifact.getGroupId();
+ String artifactId = artifact.getArtifactId();
+ String version = artifact.getVersion();
+
+ IMaven maven = MavenPlugin.getMaven();
+ IMavenProjectRegistry projectRegistry = MavenPlugin.getMavenProjectRegistry();
+
+ IMavenProjectFacade mavenProject = projectRegistry.getMavenProject(groupId, artifactId, version);
+ if (mavenProject != null) {
+ return new JavaProjectSourceContainer(JavaCore.create(mavenProject.getProject()));
+ }
+
+ try {
+ List<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
+ repositories.addAll(maven.getArtifactRepositories());
+ repositories.addAll(maven.getPluginArtifactRepositories());
+
+ if (!maven.isUnavailable(groupId, artifactId, version, "jar", "sources", repositories)) {
+ Artifact resolve = maven.resolve(groupId, artifactId, version, "jar", "sources", null, monitor);
+
+ return new ExternalArchiveSourceContainer(resolve.getFile().getAbsolutePath(), true);
+ }
+ } catch (CoreException e) {
+ // TODO maybe log, ignore otherwise
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceLookupParticipant.java b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceLookupParticipant.java
new file mode 100644
index 00000000..16954c74
--- /dev/null
+++ b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MavenSourceLookupParticipant.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 Igor Fedorenko
+ * 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:
+ * Igor Fedorenko - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2e.sourcelookup.internal.launch;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.jdt.launching.sourcelookup.advanced.AdvancedSourceLookupParticipant;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+
+
+public class MavenSourceLookupParticipant extends AdvancedSourceLookupParticipant
+ implements
+ IMavenProjectChangedListener {
+
+ @Override
+ public void init(ISourceLookupDirector director) {
+ super.init(director);
+ MavenPlugin.getMavenProjectRegistry().addMavenProjectChangedListener(this);
+ }
+
+ @Override
+ public void dispose() {
+ MavenPlugin.getMavenProjectRegistry().removeMavenProjectChangedListener(this);
+ super.dispose();
+ }
+
+ @Override
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ disposeContainers();
+ }
+}
diff --git a/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MetaInfMavenScanner.java b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MetaInfMavenScanner.java
new file mode 100644
index 00000000..77ddb23b
--- /dev/null
+++ b/org.eclipse.m2e.sourcelookup/src/org/eclipse/m2e/sourcelookup/internal/launch/MetaInfMavenScanner.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Igor Fedorenko
+ * 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:
+ * Igor Fedorenko - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2e.sourcelookup.internal.launch;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Helper to find and extract information from META-INF/maven pom.properties files.
+ */
+public abstract class MetaInfMavenScanner<T> {
+
+ private static final String META_INF_MAVEN = "META-INF/maven";
+
+ public List<T> scan(File file, String filename) {
+ List<T> result = new ArrayList<T>();
+ if (file != null) {
+ if (file.isDirectory()) {
+ scanFilesystem(new File(file, META_INF_MAVEN), filename, result);
+ } else if (file.isFile()) {
+ try {
+ try (JarFile jar = new JarFile(file)) {
+ scanJar(jar, filename, result);
+ }
+ } catch (IOException e) {
+ // fall through
+ }
+ }
+ }
+ return result;
+ }
+
+ private void scanJar(JarFile jar, String filename, List<T> result) throws IOException {
+ Enumeration<JarEntry> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ if (!entry.isDirectory()) {
+ String name = entry.getName();
+ if (name.startsWith(META_INF_MAVEN) && name.endsWith(filename)) {
+ try {
+ T t = visitJarEntry(jar, entry);
+ if (t != null) {
+ result.add(t);
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+
+ private void scanFilesystem(File dir, String filename, List<T> result) {
+ File[] files = dir.listFiles();
+ if (files == null) {
+ return;
+ }
+ for (File file : files) {
+ if (file.isDirectory()) {
+ scanFilesystem(file, filename, result);
+ } else if (file.isFile() && filename.equals(file.getName())) {
+ try {
+ T t = visitFile(file);
+ if (t != null) {
+ result.add(t);
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ protected abstract T visitFile(File file) throws IOException;
+
+ protected abstract T visitJarEntry(JarFile jar, JarEntry entry) throws IOException;
+}

Back to the top