001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.aop.aspectj.autoproxy;
018:
019: import java.util.Comparator;
020: import java.util.Iterator;
021: import java.util.LinkedList;
022: import java.util.List;
023:
024: import org.aopalliance.aop.Advice;
025: import org.aspectj.util.PartialOrder;
026: import org.aspectj.util.PartialOrder.PartialComparable;
027:
028: import org.springframework.aop.Advisor;
029: import org.springframework.aop.aspectj.AbstractAspectJAdvice;
030: import org.springframework.aop.aspectj.AspectJProxyUtils;
031: import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
032: import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
033: import org.springframework.core.Ordered;
034: import org.springframework.util.ClassUtils;
035:
036: /**
037: * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}
038: * subclass that exposes AspectJ's invocation context and understands AspectJ's rules
039: * for advice precedence when multiple pieces of advice come from the same aspect.
040: *
041: * @author Adrian Colyer
042: * @author Juergen Hoeller
043: * @since 2.0
044: */
045: public class AspectJAwareAdvisorAutoProxyCreator extends
046: AbstractAdvisorAutoProxyCreator {
047:
048: private static final Comparator DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
049:
050: /**
051: * Sort the rest by AspectJ precedence. If two pieces of advice have
052: * come from the same aspect they will have the same order.
053: * Advice from the same aspect is then further ordered according to the
054: * following rules:
055: * <ul>
056: * <li>if either of the pair is after advice, then the advice declared
057: * last gets highest precedence (runs last)</li>
058: * <li>otherwise the advice declared first gets highest precedence (runs first)</li>
059: * </ul>
060: * <p><b>Important:</b> Advisors are sorted in precedence order, from highest
061: * precedence to lowest. "On the way in" to a join point, the highest precedence
062: * advisor should run first. "On the way out" of a join point, the highest precedence
063: * advisor should run last.
064: */
065: protected List sortAdvisors(List advisors) {
066: // build list for sorting
067: List partiallyComparableAdvisors = new LinkedList();
068: for (Iterator it = advisors.iterator(); it.hasNext();) {
069: Advisor element = (Advisor) it.next();
070: PartiallyComparableAdvisorHolder advisor = new PartiallyComparableAdvisorHolder(
071: element, DEFAULT_PRECEDENCE_COMPARATOR);
072: partiallyComparableAdvisors.add(advisor);
073: }
074:
075: // sort it
076: List sorted = PartialOrder.sort(partiallyComparableAdvisors);
077: if (sorted == null) {
078: // TODO: work much harder to give a better error message here.
079: throw new IllegalArgumentException(
080: "Advice precedence circularity error");
081: }
082:
083: // extract results again
084: List result = new LinkedList();
085: for (Iterator it = sorted.iterator(); it.hasNext();) {
086: PartiallyComparableAdvisorHolder pcAdvisor = (PartiallyComparableAdvisorHolder) it
087: .next();
088: result.add(pcAdvisor.getAdvisor());
089: }
090:
091: return result;
092: }
093:
094: /**
095: * Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
096: * These additional advices are needed when using AspectJ expression pointcuts
097: * and when using AspectJ-style advice.
098: */
099: protected void extendAdvisors(List candidateAdvisors) {
100: AspectJProxyUtils
101: .makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
102: }
103:
104: /**
105: * Implements AspectJ PartialComparable interface for defining partial orderings.
106: */
107: private static class PartiallyComparableAdvisorHolder implements
108: PartialComparable {
109:
110: private final Advisor advisor;
111:
112: private final Comparator comparator;
113:
114: public PartiallyComparableAdvisorHolder(Advisor advisor,
115: Comparator comparator) {
116: this .advisor = advisor;
117: this .comparator = comparator;
118: }
119:
120: public int compareTo(Object obj) {
121: Advisor otherAdvisor = ((PartiallyComparableAdvisorHolder) obj).advisor;
122: return this .comparator.compare(this .advisor, otherAdvisor);
123: }
124:
125: public int fallbackCompareTo(Object obj) {
126: return 0;
127: }
128:
129: public Advisor getAdvisor() {
130: return this .advisor;
131: }
132:
133: public String toString() {
134: StringBuffer sb = new StringBuffer();
135: Advice advice = this .advisor.getAdvice();
136: sb.append(ClassUtils.getShortName(advice.getClass()));
137: sb.append(": ");
138: if (this .advisor instanceof Ordered) {
139: sb.append("order "
140: + ((Ordered) this .advisor).getOrder() + ", ");
141: }
142: if (advice instanceof AbstractAspectJAdvice) {
143: AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice;
144: sb.append(ajAdvice.getAspectName());
145: sb.append(", declaration order ");
146: sb.append(ajAdvice.getDeclarationOrder());
147: }
148: return sb.toString();
149: }
150: }
151:
152: }
|