Java tutorial
/* * Copyright (c) 2011-2013 GoPivotal, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package reactor.spring.context; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.AccessException; import org.springframework.expression.BeanResolver; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodResolver; import org.springframework.expression.TypedValue; import org.springframework.expression.common.TemplateAwareExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import reactor.Fn; import reactor.core.Reactor; import reactor.fn.Consumer; import reactor.fn.Event; import reactor.fn.selector.Selector; import reactor.spring.context.annotation.On; /** * @author Jon Brisbin */ public class ConsumerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { private static final List<MethodResolver> METHOD_RESOLVERS = Arrays .<MethodResolver>asList(new ReactorsMethodResolver()); private BeanResolver beanResolver; private TemplateAwareExpressionParser expressionParser = new SpelExpressionParser(); @Autowired(required = false) private ConversionService conversionService = new DefaultFormattingConversionService(); @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { beanResolver = new BeanFactoryResolver(beanFactory); } @Override public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() { @Override public void doWith(final Method method) throws IllegalArgumentException, IllegalAccessException { Annotation anno = AnnotationUtils.findAnnotation(method, On.class); if (null == anno) { return; } StandardEvaluationContext evalCtx = new StandardEvaluationContext(); evalCtx.setRootObject(bean); evalCtx.setBeanResolver(beanResolver); evalCtx.setMethodResolvers(METHOD_RESOLVERS); On onAnno = (On) anno; Object reactorObj = null; if (StringUtils.hasText(onAnno.reactor())) { Expression reactorExpr = expressionParser.parseExpression(onAnno.reactor()); reactorObj = reactorExpr.getValue(evalCtx); } Object selObj; if (StringUtils.hasText(onAnno.selector())) { try { Expression selectorExpr = expressionParser.parseExpression(onAnno.selector()); selObj = selectorExpr.getValue(evalCtx); } catch (EvaluationException e) { selObj = Fn.$(onAnno.selector()); } } else { selObj = Fn.$(method.getName()); } Consumer<Event<Object>> handler = new Consumer<Event<Object>>() { Class<?>[] argTypes = method.getParameterTypes(); @Override public void accept(Event<Object> ev) { if (argTypes.length == 0) { ReflectionUtils.invokeMethod(method, bean); return; } if (!argTypes[0].isAssignableFrom(ev.getClass()) && conversionService.canConvert(ev.getClass(), argTypes[0])) { ReflectionUtils.invokeMethod(method, bean, conversionService.convert(ev, argTypes[0])); } else { ReflectionUtils.invokeMethod(method, bean, ev); return; } if (null == ev.getData() || argTypes[0].isAssignableFrom(ev.getData().getClass())) { ReflectionUtils.invokeMethod(method, bean, ev.getData()); return; } if (conversionService.canConvert(ev.getData().getClass(), argTypes[0])) { ReflectionUtils.invokeMethod(method, bean, conversionService.convert(ev.getData(), argTypes[0])); return; } throw new IllegalArgumentException( "Cannot invoke method " + method + " passing parameter " + ev.getData()); } }; if (!(selObj instanceof Selector)) { throw new IllegalArgumentException(selObj + ", referred to by the expression '" + onAnno.selector() + "', is not a Selector"); } if (null == reactorObj) { throw new IllegalStateException("Cannot register handler with null Reactor"); } else { ((Reactor) reactorObj).on((Selector) selObj, handler); } } }); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } private static class ReactorsMethodResolver implements MethodResolver { @Override public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, List<TypeDescriptor> argumentTypes) throws AccessException { if ("$".equals(name)) { return new MethodExecutor() { @Override public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { if (arguments.length != 1 || null == arguments[0] || !Serializable.class.isAssignableFrom(arguments[0].getClass())) { return null; } Selector sel = Fn.$(arguments[0]); return new TypedValue(sel, TypeDescriptor.valueOf(sel.getClass())); } }; } else if ("R".equals(name)) { return new MethodExecutor() { @Override public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { if (arguments.length != 1 || null == arguments[0]) { return null; } Selector sel = Fn.R(arguments[0].toString()); return new TypedValue(sel, TypeDescriptor.valueOf(sel.getClass())); } }; } else if ("T".equals(name)) { return new MethodExecutor() { @Override public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { if (arguments.length != 1 || null == arguments[0] || !Class.class.isAssignableFrom(arguments[0].getClass())) { return null; } Selector sel = Fn.T((Class<?>) arguments[0]); return new TypedValue(sel, TypeDescriptor.valueOf(sel.getClass())); } }; } return null; } } }