/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.properties.editor.util;
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaProject;
import org.springframework.boot.configurationmetadata.ValueHint;
import org.springframework.ide.eclipse.boot.properties.editor.metadata.CachingValueProvider;
import org.springframework.ide.eclipse.boot.properties.editor.metadata.StsValueHint;
import org.springframework.ide.eclipse.boot.properties.editor.metadata.ValueProviderRegistry.ValueProviderStrategy;
import org.springframework.ide.eclipse.boot.util.JavaProjectUtil;
import org.springframework.ide.eclipse.boot.util.Log;
import org.springframework.ide.eclipse.editor.support.util.FuzzyMatcher;
import com.google.common.collect.ImmutableList;
import reactor.core.publisher.Flux;
/**
* @author Kris De Volder
*/
public class ResourceHintProvider implements ValueProviderStrategy {
// private static <T> Consumer<T> dbg(String msg) {
// if (DEBUG) {
// return (T x) -> {
// System.out.println(msg+": "+x);
// };
// }
// return (T x) -> {};
// }
private static final Pattern EXCLUDED = Pattern.compile(".*\\.java$");
private static String[] CLASSPATH_PREFIXES = {
"classpath:",
"classpath*:"
};
private static final String[] URL_PREFIXES = new String[] {
"classpath:",
"classpath*:",
"file:",
"http://",
"https://"
};
@Override
public Flux<StsValueHint> getValues(IJavaProject javaProject, String query) {
for (String prefix : CLASSPATH_PREFIXES) {
if (query.startsWith(prefix)) {
return classpathHints
.getValues(javaProject, query.substring(prefix.length()))
.map((hint) -> hint.prefixWith(prefix));
}
}
return Flux.fromIterable(urlPrefixHints);
}
final private ImmutableList<StsValueHint> urlPrefixHints = ImmutableList.copyOf(
Arrays.stream(URL_PREFIXES)
.map(StsValueHint::create)
.collect(Collectors.toList())
);
private ClasspathHints classpathHints = new ClasspathHints();
private static class ClasspathHints extends CachingValueProvider {
@Override
protected Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query) {
return getClasspathResourcePaths(javaProject)
.map((path) -> path.toString())
.filter((path) ->
!EXCLUDED.matcher(path).matches() &&
0!=FuzzyMatcher.matchScore(query, path)
)
.distinct()
.map((path) -> StsValueHint.create(path));
}
private Flux<IPath> getClasspathResourcePaths(IJavaProject javaProject) {
return Flux.fromArray(JavaProjectUtil.getSourceFolders(javaProject, true))
.flatMap((sourceFolder) -> {
int chopSegments = sourceFolder.getProjectRelativePath().segmentCount();
return getResourcePaths(sourceFolder)
.map((path) -> path.removeFirstSegments(chopSegments));
});
}
private Flux<IPath> getResourcePaths(IContainer folder) {
return getMembers(folder)
.flatMap((IResource member) -> {
Flux<IPath> allPaths = Flux.just(member.getProjectRelativePath());
if (member instanceof IContainer) {
allPaths = allPaths.concatWith(getResourcePaths((IContainer)member));
}
return allPaths;
});
}
private Flux<IResource> getMembers(IContainer folder) {
try {
return Flux.fromArray(folder.members());
} catch (CoreException e) {
Log.log(e);
return Flux.empty();
}
}
}
}