package org.squirrelframework.foundation.component;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.squirrelframework.foundation.component.impl.CompositePostProcessorImpl;
import org.squirrelframework.foundation.util.ClassComparator;
import org.squirrelframework.foundation.util.ReflectUtils;
import org.squirrelframework.foundation.util.TypeReference;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class SquirrelPostProcessorProvider implements SquirrelComponent, SquirrelSingleton {
private static SquirrelPostProcessorProvider instance = new SquirrelPostProcessorProvider();
public static SquirrelPostProcessorProvider getInstance() {
return instance;
}
public static void setInstance(SquirrelPostProcessorProvider instance) {
SquirrelPostProcessorProvider.instance = instance;
}
private Map<Class<?>, SquirrelPostProcessor<?>> postProcessorRegistry =
new ConcurrentHashMap<Class<?>, SquirrelPostProcessor<?>>();
/**
* Register a new post processor class for a certain component class, note existing registration
* are overwritten without warning.
*
* @param componentClass component class
* @param postProcessor post processor to be registered for component class
* @param <T> type of component class
*/
@SuppressWarnings("unchecked")
public <T> void register(Class<T> componentClass, SquirrelPostProcessor<? super T> postProcessor) {
Method method = ReflectUtils.getFirstMethodOfName(postProcessor.getClass(), "postProcess");
Class<?>[] params = method.getParameterTypes();
Preconditions.checkArgument(params.length==1, "Parameter size of method "+method.getName()+" is not match.");
Preconditions.checkArgument(params[0].isAssignableFrom(componentClass),
"Parameter type of method "+method.getName()+" is not correct.");
if(postProcessorRegistry.containsKey(componentClass)) {
SquirrelPostProcessor<? super T> existedProcessor =
(SquirrelPostProcessor<? super T>) postProcessorRegistry.get(componentClass);
if(existedProcessor instanceof CompositePostProcessorImpl) {
((CompositePostProcessorImpl<T>)existedProcessor).compose(postProcessor);
} else {
postProcessorRegistry.remove(componentClass);
CompositePostProcessorImpl<T> compositeProcessor = new CompositePostProcessorImpl<T>(existedProcessor);
compositeProcessor.compose(postProcessor);
postProcessorRegistry.put(componentClass, compositeProcessor);
}
} else {
postProcessorRegistry.put(componentClass, postProcessor);
}
}
public <T> void register(Class<T> componentClass, Class<? extends SquirrelPostProcessor<? super T>> postProcessorClass) {
SquirrelPostProcessor<? super T> postProcessor = SquirrelProvider.getInstance().newInstance(postProcessorClass);
register(componentClass, postProcessor);
}
public void unregister(Class<?> componentClass) {
postProcessorRegistry.remove(componentClass);
}
public void clearRegistry() {
postProcessorRegistry.clear();
}
@SuppressWarnings("unchecked")
public <T> SquirrelPostProcessor<T> getPostProcessor(Class<T> componentClass) {
return (SquirrelPostProcessor<T>)postProcessorRegistry.get(componentClass);
}
@SuppressWarnings("unchecked")
public <T> List<SquirrelPostProcessor<? super T>> getCallablePostProcessors(Class<T> componentClass) {
List<SquirrelPostProcessor<? super T>> postProcessors = Lists.newArrayList();
for(Entry<Class<?>, SquirrelPostProcessor<?>> entry : postProcessorRegistry.entrySet()) {
if(entry.getKey().isAssignableFrom(componentClass)) {
SquirrelPostProcessor<? super T> postProcessor = (SquirrelPostProcessor<? super T>)entry.getValue();
postProcessors.add(postProcessor);
}
}
return postProcessors;
}
public <T> SquirrelPostProcessor<? super T> getBestMatchPostProcessor(Class<T> componentClass,
Comparator<SquirrelPostProcessor<? super T>> comparator) {
List<SquirrelPostProcessor<? super T>> processors = getCallablePostProcessors(componentClass);
if (processors.isEmpty()) { return null; }
Collections.sort(processors, comparator);
return processors.get(0);
}
public <T> SquirrelPostProcessor<? super T> getBestMatchPostProcessor(Class<T> componentClass) {
return getBestMatchPostProcessor(componentClass, new ClassComparator<SquirrelPostProcessor<? super T>>());
}
public <T> void register(Class<T> componentClass, TypeReference<? extends SquirrelPostProcessor<? super T>> typeReference) {
register(componentClass, typeReference.getRawType());
}
public <T> void register(TypeReference<T> typeRefComponent, SquirrelPostProcessor<? super T> postProcessor) {
register(typeRefComponent.getRawType(), postProcessor);
}
}