/******************************************************************************* * 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.metadata; import java.util.function.Function; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchPattern; import org.springframework.boot.configurationmetadata.ValueHint; import org.springframework.ide.eclipse.boot.properties.editor.metadata.ValueProviderRegistry.ValueProviderStrategy; import org.springframework.ide.eclipse.editor.support.util.FuzzyMatcher; import org.springsource.ide.eclipse.commons.frameworks.core.async.FluxJdtSearch; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** * Abstract implementation of {@link ValueProviderStrategy} based on a JDTSearch. * <p> * All a subclass must provide is the means to create a {@link SearchPattern} and, optionally a * {@link IJavaSearchScope}. * * @author Kris De Volder */ public abstract class JdtSearchingValueProvider extends CachingValueProvider { public static String toWildCardPattern(String query) { StringBuilder builder = new StringBuilder("*"); for (char c : query.toCharArray()) { builder.append(c); builder.append('*'); } return builder.toString(); } public static SearchPattern toPackagePattern(String wildCardedQuery) { int searchFor = IJavaSearchConstants.PACKAGE; int limitTo = IJavaSearchConstants.DECLARATIONS; int matchRule = SearchPattern.R_PATTERN_MATCH; return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule); } public static SearchPattern toClassPattern(String wildCardedQuery) { int searchFor = IJavaSearchConstants.CLASS; int limitTo = IJavaSearchConstants.DECLARATIONS; int matchRule = SearchPattern.R_PATTERN_MATCH; return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule); } public static SearchPattern toTypePattern(String wildCardedQuery) { int searchFor = IJavaSearchConstants.TYPE; int limitTo = IJavaSearchConstants.DECLARATIONS; int matchRule = SearchPattern.R_PATTERN_MATCH; return SearchPattern.createPattern(wildCardedQuery, searchFor, limitTo, matchRule); } protected String asStringValue(IJavaElement element) { if (element instanceof IType) { IType type = (IType) element; return type.getFullyQualifiedName(); } else if (element instanceof IPackageFragment) { IPackageFragment pkg = (IPackageFragment) element; return pkg.getElementName(); } return null; } protected StsValueHint hint(IJavaElement e) { String fqName = asStringValue(e); return fqName==null?null:StsValueHint.create(fqName, e); } protected abstract SearchPattern toPattern(String query); protected IJavaSearchScope getScope(IJavaProject javaProject) throws JavaModelException { return FluxJdtSearch.searchScope(javaProject); } @Override public Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query) { try { return new FluxJdtSearch() .scope(getScope(javaProject)) .pattern(toPattern(query)) .search() .flatMap(getPostProcessor()) .filter((hint) -> 0!=FuzzyMatcher.matchScore(query, hint.getValue())) .distinct(StsValueHint::getValue); } catch (Exception e) { return Flux.error(e); } } protected Function<SearchMatch, Mono<StsValueHint>> getPostProcessor() { return (match) -> { Object e = match.getElement(); if (e instanceof IJavaElement) { return Mono.justOrEmpty(hint((IJavaElement)e)); } return Mono.empty(); }; } }