/* * Copyright 2002-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.springframework.aop.aspectj.autoproxy; import java.util.Comparator; import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.AspectJAopUtils; import org.springframework.aop.aspectj.AspectJPrecedenceInformation; import org.springframework.core.OrderComparator; import org.springframework.util.Assert; /** * Orders AspectJ advice/advisors by precedence (<i>not</i> invocation order). * * <p>Given two pieces of advice, <code>a</code> and <code>b</code>: * <ul> * <li>if <code>a</code> and <code>b</code> are defined in different * aspects, then the advice in the aspect with the lowest order * value has the highest precedence</li> * <li>if <code>a</code> and <code>b</code> are defined in the same * aspect, then if one of <code>a</code> or <code>b</code> is a form of * after advice, then the advice declared last in the aspect has the * highest precedence. If neither <code>a</code> nor <code>b</code> is a * form of after advice, then the advice declared first in the aspect has * the highest precedence.</li> * </ul> * * <p>Important: Note that unlike a normal comparator a return of 0 means * we don't care about the ordering, not that the two elements must be sorted * identically. Used with AspectJ PartialOrder class. * * @author Adrian Colyer * @author Juergen Hoeller * @since 2.0 */ class AspectJPrecedenceComparator implements Comparator { private static final int HIGHER_PRECEDENCE = -1; private static final int SAME_PRECEDENCE = 0; private static final int LOWER_PRECEDENCE = 1; private static final int NOT_COMPARABLE = 0; private final Comparator advisorComparator; /** * Create a default AspectJPrecedenceComparator. */ public AspectJPrecedenceComparator() { this.advisorComparator = new OrderComparator(); } /** * Create a AspectJPrecedenceComparator, using the given Comparator * for comparing {@link org.springframework.aop.Advisor} instances. * @param advisorComparator the Comparator to use for Advisors */ public AspectJPrecedenceComparator(Comparator advisorComparator) { Assert.notNull(advisorComparator, "Advisor comparator must not be null"); this.advisorComparator = advisorComparator; } public int compare(Object o1, Object o2) { if (!(o1 instanceof Advisor && o2 instanceof Advisor)) { throw new IllegalArgumentException( "AspectJPrecedenceComparator can only compare the order of Advisors, " + "but was passed [" + o1 + "] and [" + o2 + "]"); } Advisor advisor1 = (Advisor) o1; Advisor advisor2 = (Advisor) o2; boolean oneOrOtherIsAfterAdvice = (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2)); boolean oneOrOtherIsBeforeAdvice = (AspectJAopUtils.isBeforeAdvice(advisor1) || AspectJAopUtils.isBeforeAdvice(advisor2)); if (oneOrOtherIsAfterAdvice && oneOrOtherIsBeforeAdvice) { return NOT_COMPARABLE; } else { int advisorPrecedence = this.advisorComparator.compare(advisor1, advisor2); if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(advisor1, advisor2)) { advisorPrecedence = comparePrecedenceWithinAspect(advisor1, advisor2); } return advisorPrecedence; } } private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) { boolean oneOrOtherIsAfterAdvice = (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2)); int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2); if (oneOrOtherIsAfterAdvice) { // the advice declared last has higher precedence if (adviceDeclarationOrderDelta < 0) { // advice1 was declared before advice2 // so advice1 has lower precedence return LOWER_PRECEDENCE; } else if (adviceDeclarationOrderDelta == 0) { return SAME_PRECEDENCE; } else { return HIGHER_PRECEDENCE; } } else { // the advice declared first has higher precedence if (adviceDeclarationOrderDelta < 0) { // advice1 was declared before advice2 // so advice1 has higher precedence return HIGHER_PRECEDENCE; } else if (adviceDeclarationOrderDelta == 0) { return SAME_PRECEDENCE; } else { return LOWER_PRECEDENCE; } } } private boolean declaredInSameAspect(Advisor advisor1, Advisor advisor2) { if (!(hasAspectName(advisor1) && hasAspectName(advisor2))) { return false; } else { return getAspectName(advisor1).equals(getAspectName(advisor2)); } } private boolean hasAspectName(Advisor anAdvisor) { return (anAdvisor instanceof AspectJPrecedenceInformation || anAdvisor.getAdvice() instanceof AspectJPrecedenceInformation); } // pre-condition is that hasAspectName returned true private String getAspectName(Advisor anAdvisor) { return AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor).getAspectName(); } private int getAspectDeclarationOrder(Advisor anAdvisor) { AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor); if (precedenceInfo != null) { return precedenceInfo.getDeclarationOrder(); } else { return 0; } } }