InvocationController.java
package com.github.dakusui.osynth.core;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.github.dakusui.osynth.core.utils.MethodUtils.execute;
import static com.github.dakusui.osynth.core.utils.MethodUtils.toEmptyArrayIfNull;
public interface InvocationController extends InvocationHandler {
Object[] EMPTY_ARGS = new Object[0];
@Override
default Object invoke(Object proxy, Method method, Object[] args) {
InvocationContext.Impl.contextWith(method);
return execute(() -> methodHandlerFor(method).handle((SynthesizedObject) proxy, toEmptyArrayIfNull(args)));
}
MethodHandler methodHandlerFor(Method method);
MethodHandler figuredOutMethodHandlerFor(Method invokedMethod);
SynthesizedObject.Descriptor descriptor();
static InvocationContext invocationContext() {
return InvocationContext.forCurrentThread();
}
interface WithCache extends InvocationController {
/**
* Returns a newly created map object used for method handler cache.
*
* Default implementation of this method returns a new {@link ConcurrentHashMap}
* object.
* Assign the returned map of this method to a field returned by
* {@link InvocationController.WithCache#cache()} method.
*
* @return A new map for method handler cache.
*/
default Map<Method, MethodHandler> createCache() {
return new ConcurrentHashMap<>();
}
/**
* Returns an already created map object to be used for a method handler cache.
*
* @return A map for method handler cache.
*/
Map<Method, MethodHandler> cache();
default MethodHandler methodHandlerFor(Method method) {
return cache().computeIfAbsent(method, this::figuredOutMethodHandlerAndApplyDecorator);
}
default MethodHandler figuredOutMethodHandlerAndApplyDecorator(Method method) {
return descriptor()
.methodHandlerDecorator()
.apply(method, figuredOutMethodHandlerFor(method));
}
}
abstract class Base implements InvocationController {
private final SynthesizedObject.Descriptor descriptor;
protected Base(SynthesizedObject.Descriptor descriptor) {
this.descriptor = descriptor;
}
@Override
public SynthesizedObject.Descriptor descriptor() {
return this.descriptor;
}
}
}