Initial support for Gradle projects

This commit is contained in:
BoykoAlex
2017-02-07 19:45:59 -05:00
parent c1a86f7407
commit 9bef1b8a6b
62 changed files with 1721 additions and 376 deletions

View File

@@ -0,0 +1,88 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.nio.file.Path;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
public abstract class JandexClasspath implements IClasspath {
public static JavadocProviderTypes providerType = JavadocProviderTypes.HTML;
public enum JavadocProviderTypes {
JAVA_PARSER,
HTML
}
private Supplier<JandexIndex> javaIndex;
public JandexClasspath() {
this.javaIndex = Suppliers.memoize(() -> createIndex());
}
protected JandexIndex createIndex() {
Stream<Path> classpathEntries = Stream.empty();
try {
classpathEntries = getClasspathEntries();
} catch (Exception e) {
Log.log(e);
}
return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> {
switch (providerType) {
case JAVA_PARSER:
return createParserJavadocProvider(classpathResource);
default:
return createHtmlJavdocProvider(classpathResource);
}
}, getBaseIndices());
}
protected JandexIndex[] getBaseIndices() {
return new JandexIndex[0];
}
public IType findType(String fqName) {
return javaIndex.get().findType(fqName);
}
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
return javaIndex.get().fuzzySearchTypes(searchTerm, typeFilter);
}
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm) {
return javaIndex.get().fuzzySearchPackages(searchTerm);
}
public Flux<IType> allSubtypesOf(IType type) {
return javaIndex.get().allSubtypesOf(type);
}
private File findIndexFile(File jarFile) {
File indexFolder = getIndexFolder();
if (indexFolder == null) {
return null;
}
return new File(indexFolder.toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx");
}
protected File getIndexFolder() {
return JandexIndex.getIndexFolder();
}
abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource);
abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource);
}

View File

@@ -54,19 +54,29 @@ import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
public class JandexIndex {
private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
@FunctionalInterface
public static interface IndexFileFinder {
File findIndexFile(File jarFile);
}
@FunctionalInterface
public static interface JavadocProviderFactory {
IJavadocProvider createJavadocProvider(File jarContainer);
}
public static File getIndexFolder() {
File folder = new File(System.getProperty(JAVA_IO_TMPDIR), "jandex");
if (!folder.isDirectory()) {
folder.mkdirs();
}
return folder;
}
private static final IJavadocProvider ABSENT_JAVADOC_PROVIDER = new IJavadocProvider() {
@Override
public IJavadoc getJavadoc(IType type) {
return null;
@@ -86,30 +96,31 @@ public class JandexIndex {
public IJavadoc getJavadoc(IAnnotation method) {
return null;
}
};
private Map<File, Supplier<Optional<IndexView>>> index;
private JavadocProviderFactory javadocProviderFactory;
private Map<File, Supplier<List<Tuple2<String, IType>>>> knownTypes;
private Map<File, Supplier<List<String>>> knownPackages;
private Cache<File, IJavadocProvider> javadocProvidersCache = CacheBuilder.newBuilder().build();
private JandexIndex[] baseIndex;
public void setJvadocProviderFactory(JavadocProviderFactory sourceContainerProvider) {
this.javadocProviderFactory = sourceContainerProvider;
}
public JavadocProviderFactory getJavadocProviderFactory() {
return javadocProviderFactory;
}
public JandexIndex(Collection<File> classpathEntries, IndexFileFinder indexFileFinder, JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) {
public JandexIndex(Collection<File> classpathEntries, IndexFileFinder indexFileFinder,
JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) {
this.baseIndex = baseIndex;
this.index = new ConcurrentHashMap<>();
this.knownTypes = new HashMap<>();
@@ -121,186 +132,185 @@ public class JandexIndex {
knownPackages.put(file, Suppliers.memoize(() -> getKnownPackages(file).collect(Collectors.toList())));
});
}
private Optional<IndexView> createIndex(File file, IndexFileFinder indexFileFinder) {
if (file.isFile() && file.getName().endsWith(".jar")) {
if (file != null && file.isFile() && file.getName().endsWith(".jar")) {
return indexJar(file, indexFileFinder);
} else if (file.isDirectory()) {
} else if (file != null && file.isDirectory()) {
return indexFolder(file);
} else {
return Optional.empty();
}
}
private static Optional<IndexView> indexFolder(File folder) {
Indexer indexer = new Indexer();
for (Iterator<File> itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder).iterator(); itr.hasNext();) {
for (Iterator<File> itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder)
.iterator(); itr.hasNext();) {
File file = itr.next();
if (file.isFile() && file.getName().endsWith(".class")) {
try {
final InputStream stream = new FileInputStream(file);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
Log.log(e);
}
try {
final InputStream stream = new FileInputStream(file);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
Log.log(e);
}
}
}
return Optional.of(indexer.complete());
}
private static Optional<IndexView> indexJar(File file, IndexFileFinder indexFileFinder) {
File indexFile = indexFileFinder.findIndexFile(file);
if (indexFile != null) {
try {
if (indexFile.createNewFile()) {
try {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), indexFile,
false, false, false, System.out, System.err)
.getIndex());
} catch (IOException e) {
Log.log("Failed to index '" + file + "'", e);
}
} else {
try {
return Optional.of(new IndexReader(new FileInputStream(indexFile)).read());
} catch (IOException e) {
Log.log("Failed to read index file '" + indexFile + "'. Creating new index file.", e);
if (indexFile.delete()) {
return indexJar(file, indexFileFinder);
} else {
Log.log("Failed to read index file '" + indexFile);
}
File indexFile = indexFileFinder.findIndexFile(file);
if (indexFile != null) {
try {
if (indexFile.createNewFile()) {
try {
return Optional.of(JarIndexer.createJarIndex(file, new Indexer(), indexFile, false, false,
false, System.out, System.err).getIndex());
} catch (IOException e) {
Log.log("Failed to index '" + file + "'", e);
}
} else {
try {
return Optional.of(new IndexReader(new FileInputStream(indexFile)).read());
} catch (IOException e) {
Log.log("Failed to read index file '" + indexFile + "'. Creating new index file.", e);
if (indexFile.delete()) {
return indexJar(file, indexFileFinder);
} else {
Log.log("Failed to read index file '" + indexFile);
}
}
} catch (IOException e) {
Log.log("Unable to create index file '" + indexFile +"'");
}
} else {
try {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), false)
.getIndex());
} catch (IOException e) {
Log.log("Failed to index '" + file + "'", e);
}
} catch (IOException e) {
Log.log("Unable to create index file '" + indexFile + "'");
}
} else {
try {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), false)
.getIndex());
} catch (IOException e) {
Log.log("Failed to index '" + file + "'", e);
}
}
return Optional.empty();
}
public IType findType(String fqName) {
return getClassByName(DotName.createSimple(fqName));
}
IType getClassByName(DotName fqName) {
// First look for type in the base index array
return (baseIndex == null ? Stream.<IType>empty()
: Arrays.stream(baseIndex)
.filter(jandexIndex -> jandexIndex != null)
.map(jandexIndex -> jandexIndex.getClassByName(fqName)))
.filter(type -> type != null)
.findFirst()
// If not found look at indices owned by this JandexIndex instance
.orElseGet(() -> streamOfIndices()
.map(e -> Tuples.of(e.getT1(), e.getT2().getClassByName(fqName)))
.filter(e -> e.getT2() != null)
.map(e -> createType(e))
.findFirst()
.orElse(null));
: Arrays.stream(
baseIndex)
.filter(
jandexIndex -> jandexIndex != null)
.map(jandexIndex -> jandexIndex.getClassByName(fqName))).filter(type -> type != null)
.findFirst()
// If not found look at indices owned by this
// JandexIndex instance
.orElseGet(() -> streamOfIndices()
.map(e -> Tuples.of(e.getT1(), e.getT2().getClassByName(fqName)))
.filter(e -> e.getT2() != null).map(e -> createType(e)).findFirst()
.orElse(null));
}
private IType createType(Tuple2<File, ClassInfo> match) {
File classpathResource = match.getT1();
IJavadocProvider javadocProvider = null;
try {
javadocProvider = javadocProvidersCache.get(classpathResource, () -> javadocProviderFactory == null ? ABSENT_JAVADOC_PROVIDER : javadocProviderFactory.createJavadocProvider(classpathResource));
javadocProvider = javadocProvidersCache.get(classpathResource, () -> {
IJavadocProvider provider = null;
if (javadocProviderFactory != null) {
provider = javadocProviderFactory.createJavadocProvider(classpathResource);
}
return provider == null ? ABSENT_JAVADOC_PROVIDER : provider;
});
} catch (ExecutionException e) {
Log.log(e);
}
return Wrappers.wrap(this, match.getT2(), javadocProvider);
return Wrappers.wrap(this, match.getT2(), javadocProvider);
}
private Stream<Tuple2<File, IndexView>> streamOfIndices() {
return index.entrySet().parallelStream().map(e -> Tuples.of(e.getKey(), e.getValue().get())).filter(t -> t.getT2().isPresent()).map(t -> Tuples.of(t.getT1(), t.getT2().get()));
return index.entrySet().parallelStream().map(e -> Tuples.of(e.getKey(), e.getValue().get()))
.filter(t -> t.getT2().isPresent()).map(t -> Tuples.of(t.getT1(), t.getT2().get()));
}
private Stream<Tuple2<String, IType>> getKnownTypesStream(File file) {
Optional<IndexView> indexView = index.get(file).get();
if (indexView.isPresent()) {
return indexView.get().getKnownClasses().parallelStream().map(info -> Tuples.of(info.name().toString(), createType(Tuples.of(file, info))));
return indexView.get().getKnownClasses().parallelStream()
.map(info -> Tuples.of(info.name().toString(), createType(Tuples.of(file, info))));
}
return Stream.empty();
}
private Stream<String> getKnownPackages(File file) {
Optional<IndexView> indexView = index.get(file).get();
if (indexView.isPresent()) {
return indexView.get()
.getKnownClasses()
.parallelStream()
.map(info -> {
String name = info.name().toString();
return name.substring(0, name.lastIndexOf('.'));
})
.distinct();
return indexView.get().getKnownClasses().parallelStream().map(info -> {
String name = info.name().toString();
return name.substring(0, name.lastIndexOf('.'));
}).distinct();
}
return Stream.empty();
}
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
Flux<Tuple2<IType, Double>> flux = Flux.fromIterable(knownTypes.values())
.publishOn(Schedulers.parallel())
.flatMap(s -> Flux.fromIterable(s.get()))
.filter(t -> typeFilter == null || typeFilter.test(t.getT2()))
Flux<Tuple2<IType, Double>> flux = Flux.fromIterable(knownTypes.values()).publishOn(Schedulers.parallel())
.flatMap(s -> Flux.fromIterable(s.get())).filter(t -> typeFilter == null || typeFilter.test(t.getT2()))
.map(t -> Tuples.of(t.getT2(), FuzzyMatcher.matchScore(searchTerm, t.getT1())))
.filter(t -> t.getT2() != 0.0);
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm, typeFilter)));
return Flux.merge(flux,
Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm, typeFilter)));
}
}
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm) {
Flux<Tuple2<String, Double>> flux = Flux.fromIterable(knownPackages.values())
.publishOn(Schedulers.parallel())
Flux<Tuple2<String, Double>> flux = Flux.fromIterable(knownPackages.values()).publishOn(Schedulers.parallel())
.flatMap(s -> Flux.fromIterable(s.get()))
.map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg)))
.filter(t -> t.getT2() != 0.0);
.map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg))).filter(t -> t.getT2() != 0.0);
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchPackages(searchTerm)));
}
}
public Flux<IType> allSubtypesOf(IType type) {
DotName name = DotName.createSimple(type.getFullyQualifiedName());
Flux<IType> flux = Flux.fromIterable(index.keySet())
.publishOn(Schedulers.parallel())
.flatMap(file -> {
Optional<IndexView> optional = index.get(file).get();
if (optional.isPresent()) {
return Flux.fromIterable(type.isInterface() ? optional.get().getAllKnownImplementors(name) : optional.get().getAllKnownSubclasses(name))
.publishOn(Schedulers.parallel())
.map(info -> createType(Tuples.of(file, info)));
} else {
return Flux.empty();
}
});
Flux<IType> flux = Flux.fromIterable(index.keySet()).publishOn(Schedulers.parallel()).flatMap(file -> {
Optional<IndexView> optional = index.get(file).get();
if (optional.isPresent()) {
return Flux
.fromIterable(type.isInterface() ? optional.get().getAllKnownImplementors(name)
: optional.get().getAllKnownSubclasses(name))
.publishOn(Schedulers.parallel()).map(info -> createType(Tuples.of(file, info)));
} else {
return Flux.empty();
}
});
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.allSubtypesOf(type)));
}
}
}

View File

@@ -11,8 +11,12 @@
package org.springframework.ide.vscode.commons.java;
import java.nio.file.Path;
import java.util.function.Predicate;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
/**
* Classpath for a Java artifact
*
@@ -21,7 +25,21 @@ import java.util.stream.Stream;
*
*/
public interface IClasspath {
String getName();
boolean exists();
IType findType(String fqName);
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter);
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
Flux<IType> allSubtypesOf(IType type);
Path getOutputFolder();
/**
* Classpath entries paths
*

View File

@@ -10,20 +10,25 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.util.function.Predicate;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
public interface IJavaProject extends IJavaElement {
IType findType(String fqName);
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter);
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
Flux<IType> allSubtypesOf(IType type);
IClasspath getClasspath();
@Override
default String getElementName() {
return getClasspath().getName();
}
@Override
default IJavadoc getJavaDoc() {
return null;
}
@Override
default boolean exists() {
return getClasspath().exists();
}
}