/* * Copyright 2006 the original author or authors. * * 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 org.springmodules.xt.model.introductor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger; import org.springframework.aop.IntroductionInterceptor; import org.springmodules.xt.model.introductor.annotation.MapToTargetField; import org.springmodules.xt.model.introductor.annotation.OverrideTarget; /** * Abstract Spring AOP Introduction Interceptor.<br> * * @author Sergio Bossa */ public abstract class AbstractIntroductorInterceptor implements IntroductionInterceptor { private static final Logger logger = Logger.getLogger(AbstractIntroductorInterceptor.class); private Set<Class> introducedInterfaces = new HashSet<Class>(); private Map<Method, Method> introducedMethods = new HashMap<Method, Method>(); private Map<Method, Method> targetMethods = new HashMap<Method, Method>(); /** * @param introducedInterfaces The interfaces to introduce. */ public AbstractIntroductorInterceptor(Class[] introducedInterfaces) { Collections.addAll(this.introducedInterfaces, introducedInterfaces); } public boolean implementsInterface(Class aClass) { return this.isIntroduced(aClass); } /** * Get the method from the target object corresponding to the given {@link org.aopalliance.intercept.MethodInvocation}. * * @return The target method, or null if no method is found. */ protected Method getTargetMethod(MethodInvocation methodInvocation) { Object target = methodInvocation.getThis(); Method invokedMethod = methodInvocation.getMethod(); Method result = null; if (this.targetMethods.containsKey(invokedMethod)) { Method targetMethod = this.targetMethods.get(invokedMethod); logger.debug("Found cached target method: " + targetMethod.getName()); result = targetMethod; } else { List<Method> methods = Arrays.asList(target.getClass().getMethods()); for(Method targetMethod : methods) { if (targetMethod.getName().equals(invokedMethod.getName()) && Arrays.equals(targetMethod.getParameterTypes(), invokedMethod.getParameterTypes()) && targetMethod.getReturnType().equals(invokedMethod.getReturnType())) { this.targetMethods.put(invokedMethod, targetMethod); result = targetMethod; break; } } } return result; } /** * Return true if the given method is declared into an introduced interface, false otherwise. */ protected boolean isIntroduced(Method invokedMethod) { boolean result = false; if (this.introducedMethods.containsKey(invokedMethod)) { Method introducedMethod = this.introducedMethods.get(invokedMethod); logger.debug("Found cached introduced method: " + introducedMethod.getName()); result = true; } else { List<Method> methods = new LinkedList(); for (Class intf : this.introducedInterfaces) { methods.addAll(Arrays.asList(intf.getMethods())); } for(Method introducedMethod : methods) { if (introducedMethod.getName().equals(invokedMethod.getName()) && Arrays.equals(introducedMethod.getParameterTypes(), invokedMethod.getParameterTypes()) && introducedMethod.getReturnType().equals(invokedMethod.getReturnType())) { this.introducedMethods.put(invokedMethod, introducedMethod); result = true; break; } } } return result; } /** * Return true if the given class is an introduced interface, false otherwise. */ protected boolean isIntroduced(Class aClass) { if (aClass.isInterface()) { for(Class introduced : this.introducedInterfaces) { if (aClass.isAssignableFrom(introduced)) { return true; } } } return false; } /** * Return true if the {@link org.springmodules.xt.model.introductor.annotation.MapToTargetField} * annotation is applied to the given method, false otherwise. */ protected boolean shouldMapToTargetField(Method aMethod) { if (this.isIntroduced(aMethod)) { Method introducedMethod = this.introducedMethods.get(aMethod); if (introducedMethod.isAnnotationPresent(MapToTargetField.class)) { logger.debug("Found annotation: " + MapToTargetField.class); return true; } else { return false; } } else { return false; } } /** * Return true if the {@link org.springmodules.xt.model.introductor.annotation.OverrideTarget} * annotation is applied to the given method, false otherwise. */ protected boolean shouldOverrideTarget(Method aMethod) { if (this.isIntroduced(aMethod)) { Method introducedMethod = this.introducedMethods.get(aMethod); if (introducedMethod.isAnnotationPresent(OverrideTarget.class)) { logger.debug("Found annotation: " + OverrideTarget.class); return true; } else { return false; } } else { return false; } } }