View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.aop.aspectj;
18  
19  import java.lang.reflect.Method;
20  
21  import org.aspectj.lang.ProceedingJoinPoint;
22  import org.junit.Before;
23  import org.junit.Test;
24  
25  import org.springframework.aop.MethodBeforeAdvice;
26  import org.springframework.beans.factory.BeanNameAware;
27  import org.springframework.context.support.ClassPathXmlApplicationContext;
28  import org.springframework.core.Ordered;
29  import org.springframework.tests.sample.beans.ITestBean;
30  
31  import static org.junit.Assert.*;
32  
33  /**
34   * @author Adrian Colyer
35   * @author Chris Beams
36   */
37  public final class AspectAndAdvicePrecedenceTests {
38  
39  	private PrecedenceTestAspect highPrecedenceAspect;
40  
41  	private PrecedenceTestAspect lowPrecedenceAspect;
42  
43  	private SimpleSpringBeforeAdvice highPrecedenceSpringAdvice;
44  
45  	private SimpleSpringBeforeAdvice lowPrecedenceSpringAdvice;
46  
47  	private ITestBean testBean;
48  
49  
50  	@Before
51  	public void setUp() {
52  		ClassPathXmlApplicationContext ctx =
53  			new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
54  		highPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("highPrecedenceAspect");
55  		lowPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("lowPrecedenceAspect");
56  		highPrecedenceSpringAdvice = (SimpleSpringBeforeAdvice) ctx.getBean("highPrecedenceSpringAdvice");
57  		lowPrecedenceSpringAdvice = (SimpleSpringBeforeAdvice) ctx.getBean("lowPrecedenceSpringAdvice");
58  		testBean = (ITestBean) ctx.getBean("testBean");
59  	}
60  
61  	// ========== end of test case set up, start of tests proper ===================
62  
63  	@Test
64  	public void testAdviceOrder() {
65  		PrecedenceTestAspect.Collaborator collaborator = new PrecedenceVerifyingCollaborator();
66  		this.highPrecedenceAspect.setCollaborator(collaborator);
67  		this.lowPrecedenceAspect.setCollaborator(collaborator);
68  		this.highPrecedenceSpringAdvice.setCollaborator(collaborator);
69  		this.lowPrecedenceSpringAdvice.setCollaborator(collaborator);
70  		this.testBean.getAge();
71  	}
72  
73  
74  	private static class PrecedenceVerifyingCollaborator implements PrecedenceTestAspect.Collaborator {
75  
76  		private static final String[] EXPECTED = {
77  			// this order confirmed by running the same aspects (minus the Spring AOP advisors)
78  			// through AspectJ...
79  			"beforeAdviceOne(highPrecedenceAspect)",  	       // 1
80  			"beforeAdviceTwo(highPrecedenceAspect)",           // 2
81  			"aroundAdviceOne(highPrecedenceAspect)",           // 3, before proceed
82  			  "aroundAdviceTwo(highPrecedenceAspect)",         // 4, before proceed
83  			    "beforeAdviceOne(highPrecedenceSpringAdvice)", // 5
84  			    "beforeAdviceOne(lowPrecedenceSpringAdvice)",  // 6
85  			    "beforeAdviceOne(lowPrecedenceAspect)",        // 7
86  			    "beforeAdviceTwo(lowPrecedenceAspect)",        // 8
87  			    "aroundAdviceOne(lowPrecedenceAspect)",        // 9, before proceed
88  			      "aroundAdviceTwo(lowPrecedenceAspect)",      // 10, before proceed
89  			      "aroundAdviceTwo(lowPrecedenceAspect)",      // 11, after proceed
90  			    "aroundAdviceOne(lowPrecedenceAspect)",        // 12, after proceed
91  			    "afterAdviceOne(lowPrecedenceAspect)",         // 13
92  			    "afterAdviceTwo(lowPrecedenceAspect)",         // 14
93  			  "aroundAdviceTwo(highPrecedenceAspect)",         // 15, after proceed
94  			"aroundAdviceOne(highPrecedenceAspect)",           // 16, after proceed
95  			"afterAdviceOne(highPrecedenceAspect)",            // 17
96  			"afterAdviceTwo(highPrecedenceAspect)"             // 18
97  		};
98  
99  		private int adviceInvocationNumber = 0;
100 
101 		private void checkAdvice(String whatJustHappened) {
102 			//System.out.println("[" + adviceInvocationNumber + "] " + whatJustHappened + " ==> " + EXPECTED[adviceInvocationNumber]);
103 			if (adviceInvocationNumber > (EXPECTED.length - 1)) {
104 				fail("Too many advice invocations, expecting " + EXPECTED.length
105 						+ " but had " + adviceInvocationNumber);
106 			}
107 			String expecting = EXPECTED[adviceInvocationNumber++];
108 			if (!whatJustHappened.equals(expecting)) {
109 				fail("Expecting '" + expecting + "' on advice invocation " + adviceInvocationNumber +
110 						" but got '" + whatJustHappened + "'");
111 			}
112 		}
113 
114 		@Override
115 		public void beforeAdviceOne(String beanName) {
116 			checkAdvice("beforeAdviceOne(" + beanName + ")");
117 		}
118 
119 		@Override
120 		public void beforeAdviceTwo(String beanName) {
121 			checkAdvice("beforeAdviceTwo(" + beanName + ")");
122 		}
123 
124 		@Override
125 		public void aroundAdviceOne(String beanName) {
126 			checkAdvice("aroundAdviceOne(" + beanName + ")");
127 		}
128 
129 		@Override
130 		public void aroundAdviceTwo(String beanName) {
131 			checkAdvice("aroundAdviceTwo(" + beanName + ")");
132 		}
133 
134 		@Override
135 		public void afterAdviceOne(String beanName) {
136 			checkAdvice("afterAdviceOne(" + beanName + ")");
137 		}
138 
139 		@Override
140 		public void afterAdviceTwo(String beanName) {
141 			checkAdvice("afterAdviceTwo(" + beanName + ")");
142 		}
143 	}
144 
145 }
146 
147 
148 class PrecedenceTestAspect implements BeanNameAware, Ordered {
149 
150 	private String name;
151 
152 	private int order = Ordered.LOWEST_PRECEDENCE;
153 
154 	private Collaborator collaborator;
155 
156 
157 	@Override
158 	public void setBeanName(String name) {
159 		this.name = name;
160 	}
161 
162 	public void setOrder(int order) {
163 		this.order = order;
164 	}
165 
166 	@Override
167 	public int getOrder() {
168 		return order;
169 	}
170 
171 	public void setCollaborator(Collaborator collaborator) {
172 		this.collaborator = collaborator;
173 	}
174 
175 	public void beforeAdviceOne() {
176 		this.collaborator.beforeAdviceOne(this.name);
177 	}
178 
179 	public void beforeAdviceTwo() {
180 		this.collaborator.beforeAdviceTwo(this.name);
181 	}
182 
183 	public int aroundAdviceOne(ProceedingJoinPoint pjp) {
184 		int ret = -1;
185 		this.collaborator.aroundAdviceOne(this.name);
186 		try {
187 			ret = ((Integer)pjp.proceed()).intValue();
188 		}
189 		catch(Throwable t) { throw new RuntimeException(t); }
190 		this.collaborator.aroundAdviceOne(this.name);
191 		return ret;
192 	}
193 
194 	public int aroundAdviceTwo(ProceedingJoinPoint pjp) {
195 		int ret = -1;
196 		this.collaborator.aroundAdviceTwo(this.name);
197 		try {
198 			ret = ((Integer)pjp.proceed()).intValue();
199 		}
200 		catch(Throwable t) {throw new RuntimeException(t);}
201 		this.collaborator.aroundAdviceTwo(this.name);
202 		return ret;
203 	}
204 
205 	public void afterAdviceOne() {
206 		this.collaborator.afterAdviceOne(this.name);
207 	}
208 
209 	public void afterAdviceTwo() {
210 		this.collaborator.afterAdviceTwo(this.name);
211 	}
212 
213 
214 	public interface Collaborator {
215 
216 		void beforeAdviceOne(String beanName);
217 		void beforeAdviceTwo(String beanName);
218 		void aroundAdviceOne(String beanName);
219 		void aroundAdviceTwo(String beanName);
220 		void afterAdviceOne(String beanName);
221 		void afterAdviceTwo(String beanName);
222 	}
223 
224 }
225 
226 
227 class SimpleSpringBeforeAdvice implements MethodBeforeAdvice, BeanNameAware {
228 
229 	private PrecedenceTestAspect.Collaborator collaborator;
230 	private String name;
231 
232 	/* (non-Javadoc)
233 	 * @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
234 	 */
235 	@Override
236 	public void before(Method method, Object[] args, Object target)
237 			throws Throwable {
238 		this.collaborator.beforeAdviceOne(this.name);
239 	}
240 
241 	public void setCollaborator(PrecedenceTestAspect.Collaborator collaborator) {
242 		this.collaborator = collaborator;
243 	}
244 
245 	/* (non-Javadoc)
246 	 * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
247 	 */
248 	@Override
249 	public void setBeanName(String name) {
250 		this.name = name;
251 	}
252 
253 }