Additional cleanup and refactoring in ContextFunctionCatalog

This commit is contained in:
Oleg Zhurakousky
2019-02-06 00:02:50 +01:00
parent 6a2717a580
commit 79cdf3c9b5

View File

@@ -115,7 +115,7 @@ public class ContextFunctionCatalogAutoConfiguration {
@Override
public FunctionRegistration<?> getRegistration(Object function) {
return this.processor.getRegistration(function);
return function == null ? null : this.processor.getRegistration(function);
}
@Override
@@ -125,6 +125,27 @@ public class ContextFunctionCatalogAutoConfiguration {
this.processor.register(registration);
}
@Override
public Set<String> getNames(Class<?> type) {
if (Supplier.class.isAssignableFrom(type)) {
return this.processor.suppliers.keySet();
}
if (Consumer.class.isAssignableFrom(type)) {
return this.processor.consumers.keySet();
}
if (Function.class.isAssignableFrom(type)) {
return this.processor.functions.keySet();
}
return Collections.emptySet();
}
@Override
public int size() {
return this.processor.suppliers.size()
+ this.processor.functions.size()
+ this.processor.consumers.size();
}
@Override
@SuppressWarnings("unchecked")
protected <T> T doLookup(Class<?> type, String name) {
@@ -150,55 +171,6 @@ public class ContextFunctionCatalogAutoConfiguration {
return function;
}
@Override
public Set<String> getNames(Class<?> type) {
if (Supplier.class.isAssignableFrom(type)) {
return this.processor.getSuppliers();
}
if (Consumer.class.isAssignableFrom(type)) {
return this.processor.getConsumers();
}
if (Function.class.isAssignableFrom(type)) {
return this.processor.getFunctions();
}
return Collections.emptySet();
}
@Override
public int size() {
return this.processor.getSuppliers().size()
+ this.processor.getFunctions().size()
+ this.processor.getConsumers().size();
}
}
@Configuration
@ConditionalOnClass(Gson.class)
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrMissingJacksonCondition.class)
protected static class GsonConfiguration {
@Bean
public GsonMapper jsonMapper(Gson gson) {
return new GsonMapper(gson);
}
}
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
// @checkstyle:off
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
// @checkstyle:on
protected static class JacksonConfiguration {
@Bean
public JacksonMapper jsonMapper(ObjectMapper mapper) {
return new JacksonMapper(mapper);
}
}
@Component
@@ -207,22 +179,20 @@ public class ContextFunctionCatalogAutoConfiguration {
private Log logger = LogFactory.getLog(ContextFunctionRegistry.class);
private ApplicationEventPublisher applicationEventPublisher;
private ConfigurableListableBeanFactory beanFactory;
private Map<String, Object> suppliers = new ConcurrentHashMap<>();
private Map<String, Object> functions = new ConcurrentHashMap<>();
private Map<String, Object> consumers = new ConcurrentHashMap<>();
private ApplicationEventPublisher applicationEventPublisher;
private ConfigurableListableBeanFactory beanFactory;
private Map<Object, String> names = new ConcurrentHashMap<>();
private Map<String, FunctionType> types = new ConcurrentHashMap<>();
private Map<String, Object> allFunctions = new ConcurrentHashMap<>();
/**
* Will collect all suppliers, functions, consumers and function registration as
* late as possible in the lifecycle.
@@ -273,48 +243,34 @@ public class ContextFunctionCatalogAutoConfiguration {
}
FunctionRegistration<?> getRegistration(Object function) {
if (function == null || !this.names.containsKey(function)) {
return null;
if (names.containsKey(function)) {
return new FunctionRegistration<>(function, this.names.get(function))
.type(findType(function).getType());
}
return new FunctionRegistration<>(function, this.names.get(function))
.type(findType(function).getType());
return null;
}
Supplier<?> lookupSupplier(String name) {
Object function = compose(name);
if (function instanceof Supplier) {
return (Supplier<?>) function;
}
else {
logger.warn("The resulting composition is is of type "
+ types.get(normalizeName(name))
+ " and can not be cast to Supplier");
}
return null;
return (Supplier<?>) lookup(name, this.suppliers, Supplier.class);
}
Function<?, ?> lookupFunction(String name) {
Object function = compose(name);
if (function instanceof Function) {
return (Function<?, ?>) function;
}
else {
logger.warn("The resulting composition is is of type "
+ types.get(normalizeName(name))
+ " and can not be cast to Function");
}
return null;
return (Function<?, ?>) lookup(name, this.functions, Function.class);
}
Consumer<?> lookupConsumer(String name) {
Object function = compose(name);
if (function instanceof Consumer) {
return (Consumer<?>) function;
return (Consumer<?>) lookup(name, this.consumers, Consumer.class);
}
@SuppressWarnings("unchecked")
private Object lookup(String name, @SuppressWarnings("rawtypes") Map lookup, Class<?> typeOfFunction) {
Object function = compose(name, lookup);
if (function != null && typeOfFunction.isAssignableFrom(function.getClass())) {
return function;
}
else {
logger.warn("The resulting composition is is of type "
+ types.get(normalizeName(name))
+ " and can not be cast to Consumer");
+ types.get(normalizeName(name)));
}
return null;
}
@@ -337,39 +293,22 @@ public class ContextFunctionCatalogAutoConfiguration {
return name.replaceAll(",", "|").trim();
}
private Set<String> getSuppliers() {
return this.suppliers.keySet();
}
private Set<String> getFunctions() {
return this.functions.keySet();
}
private Set<String> getConsumers() {
return this.consumers.keySet();
}
private Object compose(String name) {
private Object compose(String name, Map<String, Object> lookup) {
name = normalizeName(name);
Object composedFunction = null;
if (allFunctions.containsKey(name)) {
composedFunction = allFunctions.get(name);
if (lookup.containsKey(name)) {
composedFunction = lookup.get(name);
}
else {
/*
* Need to revisit since "" implies a single function or supplier or... By
* using combined map we may have a single function but multiple consumers
* scenario
*/
if (name.equals("") && allFunctions.size() == 1) {
composedFunction = allFunctions.values().iterator().next();
if (name.equals("") && lookup.size() == 1) {
composedFunction = lookup.values().iterator().next();
}
else {
String[] stages = StringUtils.delimitedListToStringArray(name, "|");
if (Stream.of(stages)
.allMatch(funcName -> allFunctions.containsKey(funcName))) {
.allMatch(funcName -> contains(funcName))) {
List<Object> composableFunctions = Stream.of(stages)
.map(funcName -> allFunctions.get(funcName))
.map(funcName -> find(funcName))
.collect(Collectors.toList());
composedFunction = composableFunctions.stream()
.reduce((a, z) -> composeFunctions(a, z))
@@ -382,7 +321,7 @@ public class ContextFunctionCatalogAutoConfiguration {
.get(stages[stages.length - 1]);
this.types.put(name, FunctionType.compose(input, output));
this.names.put(composedFunction, name);
allFunctions.put(name, composedFunction);
lookup.put(name, composedFunction);
}
}
}
@@ -390,6 +329,21 @@ public class ContextFunctionCatalogAutoConfiguration {
return composedFunction;
}
private boolean contains(String name) {
return suppliers.containsKey(name) || functions.containsKey(name) || consumers.containsKey(name);
}
private Object find(String name) {
Object result = suppliers.get(name);
if (result == null) {
result = functions.get(name);
}
if (result == null) {
result = consumers.get(name);
}
return result;
}
@SuppressWarnings("unchecked")
private Object composeFunctions(Object a, Object b) {
if (a instanceof Supplier && b instanceof Function) {
@@ -471,21 +425,18 @@ public class ContextFunctionCatalogAutoConfiguration {
type = Supplier.class;
for (String name : registration.getNames()) {
this.suppliers.put(name, registration.getTarget());
this.allFunctions.put(name, registration.getTarget());
}
}
else if (target instanceof Consumer) {
type = Consumer.class;
for (String name : registration.getNames()) {
this.consumers.put(name, registration.getTarget());
this.allFunctions.put(name, registration.getTarget());
}
}
else if (target instanceof Function) {
type = Function.class;
for (String name : registration.getNames()) {
this.functions.put(name, registration.getTarget());
this.allFunctions.put(name, registration.getTarget());
}
}
else {
@@ -539,21 +490,18 @@ public class ContextFunctionCatalogAutoConfiguration {
Object target = registration.getTarget();
boolean isolated = getClass().getClassLoader() != target.getClass()
.getClassLoader();
if (target instanceof Supplier<?>) {
if (isolated) {
if (isolated) {
if (target instanceof Supplier<?> && isolated) {
target = new IsolatedSupplier((Supplier<?>) target);
}
}
else if (target instanceof Function<?, ?>) {
if (isolated) {
else if (target instanceof Function<?, ?>) {
target = new IsolatedFunction((Function<?, ?>) target);
}
}
else if (target instanceof Consumer<?>) {
if (isolated) {
else if (target instanceof Consumer<?>) {
target = new IsolatedConsumer((Consumer<?>) target);
}
}
registration.target(target);
return registration;
}
@@ -668,4 +616,33 @@ public class ContextFunctionCatalogAutoConfiguration {
}
@Configuration
@ConditionalOnClass(Gson.class)
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrMissingJacksonCondition.class)
protected static class GsonConfiguration {
@Bean
public GsonMapper jsonMapper(Gson gson) {
return new GsonMapper(gson);
}
}
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
// @checkstyle:off
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
// @checkstyle:on
protected static class JacksonConfiguration {
@Bean
public JacksonMapper jsonMapper(ObjectMapper mapper) {
return new JacksonMapper(mapper);
}
}
}