/*******************************************************************************
* 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.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.IJavaProject;
import org.springframework.boot.configurationmetadata.ValueHint;
import org.springframework.boot.configurationmetadata.ValueProvider;
import org.springframework.ide.eclipse.editor.support.util.CollectionUtil;
import reactor.core.publisher.Flux;
/**
* An instance of this class serves as a 'registry' that associates known
* {@link ValueProvider} ids to strategy objects used in the computation of completions
* for properties to which the provider is attached.
*
* @author Kris De Volder
*/
public class ValueProviderRegistry {
private static ValueProviderRegistry DEFAULT;
/**
* Creates a default {@link ValueProviderRegistry} which is initialized with all the known
* providers. (This is the one production code should use, test code might make use
* something else for mocking purposes).
*/
public synchronized static ValueProviderRegistry getDefault() {
if (DEFAULT==null) {
DEFAULT = new ValueProviderRegistry();
DEFAULT.initializeDefaults(DEFAULT);
}
return DEFAULT;
}
protected void initializeDefaults(ValueProviderRegistry r) {
def("logger-name", LoggerNameProvider.FACTORY);
def("class-reference", ClassReferenceProvider.FACTORY);
}
private Map<String, Function<Map<String, Object>, ValueProviderStrategy>> registry = new HashMap<>();
public interface ValueProviderStrategy {
Flux<StsValueHint> getValues(IJavaProject javaProject, String query);
default Collection<StsValueHint> getValuesNow(IJavaProject javaProject, String query) {
return this.getValues(javaProject, query)
.take(CachingValueProvider.TIMEOUT)
.collectList()
.block();
}
}
/**
* Defines a value provider by binding its id to a strategy.
*/
public void def(String id, Function<Map<String, Object>, ValueProviderStrategy> algo) {
Assert.isLegal(!registry.containsKey(id));
registry.put(id, algo);
}
/**
* Resolve a list of {@link ValueProvider}s to a {@link ValueProviderStrategy}.
* <p>
* Essentially this finds the first provider from the list which has a known name
* and uses that to iinstantiate a ValueProviderStrategy. Spring boot assumes that
* a list is provided to allow new providers to be defined that override older ones
* and these are added at the top of the list. Thus an older IDE can continue to
* function using the older provider further down the list whereas newer IDEs will
* use a 'better' one from higher up the list.
*/
public ValueProviderStrategy resolve(List<ValueProvider> providerDescriptors) {
if (CollectionUtil.hasElements(providerDescriptors)) {
for (ValueProvider descriptor : providerDescriptors) {
Function<Map<String, Object>, ValueProviderStrategy> factory = registry.get(descriptor.getName());
if (factory!=null) {
Map<String, Object> params = descriptor.getParameters();
return factory.apply(params);
}
}
}
return null;
}
}