com.netflix.governator.providers.AdvisedProvider Maven / Gradle / Ivy
package com.netflix.governator.providers;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderWithExtensionVisitor;
import com.google.inject.spi.Toolable;
import com.google.inject.util.Types;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.UnaryOperator;
import javax.inject.Provider;
class AdvisedProvider implements ProviderWithExtensionVisitor, HasDependencies {
private final Set> dependencies = new HashSet<>();
private final String name;
private final Provider delegate;
private final List>> adviceBindings = new ArrayList<>();
private final TypeLiteral> advisesType;
public AdvisedProvider(TypeLiteral typeLiteral, String name, Annotation annotation, Provider delegate) {
this.name = name;
this.delegate = delegate;
this.advisesType = (TypeLiteral>) TypeLiteral.get(Types.newParameterizedType(UnaryOperator.class, typeLiteral.getType()));
}
@Override
public T get() {
return adviceBindings
.stream()
.map(advice -> advice.binding.getProvider().get())
.reduce(delegate.get(),
(advised, advice) -> advice.apply(advised),
(current, next) -> next);
}
@Override
public Set> getDependencies() {
return dependencies;
}
@Override
public V acceptExtensionVisitor(BindingTargetVisitor visitor,
ProviderInstanceBinding extends B> binding) {
return visitor.visit(binding);
}
@SuppressWarnings("unchecked")
@Toolable
@javax.inject.Inject
protected void initialize(Injector injector) {
for (Binding> binding : injector.findBindingsByType(advisesType)) {
Key> bindingKey = binding.getKey();
if (bindingKey.hasAttributes() && AdviceElement.class.isAssignableFrom(bindingKey.getAnnotationType())) {
AdviceElementImpl adviceElement = (AdviceElementImpl) bindingKey.getAnnotation();
if (name.equals(adviceElement.name())) {
if (adviceElement.type() == AdviceElement.Type.ADVICE) {
adviceBindings.add(new ProvisionAdviceHolder>((Binding>) binding, adviceElement.getOrder()));
}
dependencies.add(Dependency.get(bindingKey));
}
}
}
adviceBindings.sort(ByOrder);
}
static Comparator> ByOrder = new Comparator>() {
@Override
public int compare(ProvisionAdviceHolder> o1, ProvisionAdviceHolder> o2) {
int rv = Integer.compare(o1.order, o2.order);
if (rv == 0) {
return Integer.compare(System.identityHashCode(o1.hashCode()), System.identityHashCode(o2.hashCode()));
}
return rv;
}
};
static class ProvisionAdviceHolder {
Binding binding;
int order;
public ProvisionAdviceHolder(Binding binding, int order) {
this.order = order;
this.binding = binding;
}
}
}