com.github.dakusui.floorplan.component.Configurator Maven / Gradle / Ivy
package com.github.dakusui.floorplan.component;
import com.github.dakusui.floorplan.exception.Exceptions;
import com.github.dakusui.floorplan.policy.Policy;
import com.github.dakusui.floorplan.resolver.Resolver;
import com.github.dakusui.floorplan.utils.FloorPlanUtils;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import static com.github.dakusui.floorplan.utils.Checks.require;
import static com.github.dakusui.floorplan.utils.Checks.requireNonNull;
import static java.util.stream.Collectors.toMap;
public interface Configurator extends AttributeBundle {
Configurator configure(A attr, Resolver resolver);
Configurator addOperatorFactory(Operator.Factory operator);
Component build(Policy policy, Map> pool);
/**
* Returns a resolver for a specified attribute {@code attr} set to this object
* itself. If it is not present, an empty {@code Optional} will be returned.
*
* @param attr An attribute for which a resolver is searched.
* @param Type of a value of an attribute {@code attr}.
* @return An optional of a resolver for the given attribute {@code attr}.
*/
Optional> resolverFor(A attr);
/**
* Returns a resolver for a specified attribute {@code attr}. If no resolver is
* set to this object, this method returns tries to find a resolver from a
* given {@code policy} object.
*
* @param attr An attribute for which a resolver will be returned.
* @param policy A policy object from which a resolver is searched.
* @param A type of attribute value.
* @return A resolver for the given attribute {@code attr}.
*/
default Resolver super A, T> resolverFor(A attr, Policy policy) {
require(
attr,
(A a) -> a.spec().getClass().isAssignableFrom(this.spec().getClass()),
n -> Exceptions.inconsistentSpec(() ->
String.format("An attribute '%s' is not compatible with '%s'", n.name(), this.spec())
));
return this.resolverFor(attr).orElseGet(() -> policy.fallbackResolverFor(this.ref(), attr));
}
class Impl implements Configurator {
private final ComponentSpec spec;
private final Map> resolvers = new LinkedHashMap<>();
private final Ref ref;
private final Map> operatorFactories;
Impl(ComponentSpec spec, String id) {
this.spec = spec;
this.ref = Ref.ref(this.spec, id);
this.operatorFactories = this.spec.operatorFactories();
}
@Override
public Ref ref() {
return this.ref;
}
@Override
public ComponentSpec spec() {
return this.spec;
}
@SuppressWarnings("unchecked")
@Override
public Optional> resolverFor(A attr) {
return resolvers.containsKey(attr) ?
Optional.of((Resolver) resolvers.get(attr)) :
Optional.empty();
}
@Override
public Configurator configure(A attr, Resolver resolver) {
this.resolvers.put(
attr,
resolver
);
return this;
}
@SuppressWarnings("unchecked")
@Override
public Configurator addOperatorFactory(Operator.Factory operatorFactory) {
this.operatorFactories.put(requireNonNull(operatorFactory.type()), requireNonNull(operatorFactory));
return this;
}
@Override
public Component build(Policy policy, Map> pool) {
return new Component.Impl<>(
this.ref,
new LinkedHashMap() {{
spec.attributes().forEach(
(A attr) -> {
Object u;
put(attr,
require(
u = FloorPlanUtils.resolve(attr, Impl.this, policy),
attr::test,
Exceptions.typeMismatch(attr, u)
));
});
}},
operatorFactories.entrySet().stream().map(this::convertEntry
).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)),
pool
);
}
Map.Entry> convertEntry(Map.Entry> inEntry) {
return new Map.Entry>() {
Operator value = inEntry.getValue().apply(spec());
@Override
public Operator.Type getKey() {
return inEntry.getKey();
}
@Override
public Operator getValue() {
return value;
}
@Override
public Operator setValue(Operator value) {
this.value = value;
return value;
}
};
}
@Override
public String toString() {
return String.format("configurator(%s)", this.ref);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy