/*
* Copyright 2002-2013 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;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.tests.sample.beans.ITestBean;
import static org.junit.Assert.*;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectAndAdvicePrecedenceTests {
private PrecedenceTestAspect highPrecedenceAspect;
private PrecedenceTestAspect lowPrecedenceAspect;
private SimpleSpringBeforeAdvice highPrecedenceSpringAdvice;
private SimpleSpringBeforeAdvice lowPrecedenceSpringAdvice;
private ITestBean testBean;
@Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
highPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("highPrecedenceAspect");
lowPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("lowPrecedenceAspect");
highPrecedenceSpringAdvice = (SimpleSpringBeforeAdvice) ctx.getBean("highPrecedenceSpringAdvice");
lowPrecedenceSpringAdvice = (SimpleSpringBeforeAdvice) ctx.getBean("lowPrecedenceSpringAdvice");
testBean = (ITestBean) ctx.getBean("testBean");
}
// ========== end of test case set up, start of tests proper ===================
@Test
public void testAdviceOrder() {
PrecedenceTestAspect.Collaborator collaborator = new PrecedenceVerifyingCollaborator();
this.highPrecedenceAspect.setCollaborator(collaborator);
this.lowPrecedenceAspect.setCollaborator(collaborator);
this.highPrecedenceSpringAdvice.setCollaborator(collaborator);
this.lowPrecedenceSpringAdvice.setCollaborator(collaborator);
this.testBean.getAge();
}
private static class PrecedenceVerifyingCollaborator implements PrecedenceTestAspect.Collaborator {
private static final String[] EXPECTED = {
// this order confirmed by running the same aspects (minus the Spring AOP advisors)
// through AspectJ...
"beforeAdviceOne(highPrecedenceAspect)", // 1
"beforeAdviceTwo(highPrecedenceAspect)", // 2
"aroundAdviceOne(highPrecedenceAspect)", // 3, before proceed
"aroundAdviceTwo(highPrecedenceAspect)", // 4, before proceed
"beforeAdviceOne(highPrecedenceSpringAdvice)", // 5
"beforeAdviceOne(lowPrecedenceSpringAdvice)", // 6
"beforeAdviceOne(lowPrecedenceAspect)", // 7
"beforeAdviceTwo(lowPrecedenceAspect)", // 8
"aroundAdviceOne(lowPrecedenceAspect)", // 9, before proceed
"aroundAdviceTwo(lowPrecedenceAspect)", // 10, before proceed
"aroundAdviceTwo(lowPrecedenceAspect)", // 11, after proceed
"aroundAdviceOne(lowPrecedenceAspect)", // 12, after proceed
"afterAdviceOne(lowPrecedenceAspect)", // 13
"afterAdviceTwo(lowPrecedenceAspect)", // 14
"aroundAdviceTwo(highPrecedenceAspect)", // 15, after proceed
"aroundAdviceOne(highPrecedenceAspect)", // 16, after proceed
"afterAdviceOne(highPrecedenceAspect)", // 17
"afterAdviceTwo(highPrecedenceAspect)" // 18
};
private int adviceInvocationNumber = 0;
private void checkAdvice(String whatJustHappened) {
//System.out.println("[" + adviceInvocationNumber + "] " + whatJustHappened + " ==> " + EXPECTED[adviceInvocationNumber]);
if (adviceInvocationNumber > (EXPECTED.length - 1)) {
fail("Too many advice invocations, expecting " + EXPECTED.length
+ " but had " + adviceInvocationNumber);
}
String expecting = EXPECTED[adviceInvocationNumber++];
if (!whatJustHappened.equals(expecting)) {
fail("Expecting '" + expecting + "' on advice invocation " + adviceInvocationNumber +
" but got '" + whatJustHappened + "'");
}
}
@Override
public void beforeAdviceOne(String beanName) {
checkAdvice("beforeAdviceOne(" + beanName + ")");
}
@Override
public void beforeAdviceTwo(String beanName) {
checkAdvice("beforeAdviceTwo(" + beanName + ")");
}
@Override
public void aroundAdviceOne(String beanName) {
checkAdvice("aroundAdviceOne(" + beanName + ")");
}
@Override
public void aroundAdviceTwo(String beanName) {
checkAdvice("aroundAdviceTwo(" + beanName + ")");
}
@Override
public void afterAdviceOne(String beanName) {
checkAdvice("afterAdviceOne(" + beanName + ")");
}
@Override
public void afterAdviceTwo(String beanName) {
checkAdvice("afterAdviceTwo(" + beanName + ")");
}
}
}
class PrecedenceTestAspect implements BeanNameAware, Ordered {
private String name;
private int order = Ordered.LOWEST_PRECEDENCE;
private Collaborator collaborator;
@Override
public void setBeanName(String name) {
this.name = name;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return order;
}
public void setCollaborator(Collaborator collaborator) {
this.collaborator = collaborator;
}
public void beforeAdviceOne() {
this.collaborator.beforeAdviceOne(this.name);
}
public void beforeAdviceTwo() {
this.collaborator.beforeAdviceTwo(this.name);
}
public int aroundAdviceOne(ProceedingJoinPoint pjp) {
int ret = -1;
this.collaborator.aroundAdviceOne(this.name);
try {
ret = ((Integer)pjp.proceed()).intValue();
}
catch (Throwable t) {
throw new RuntimeException(t);
}
this.collaborator.aroundAdviceOne(this.name);
return ret;
}
public int aroundAdviceTwo(ProceedingJoinPoint pjp) {
int ret = -1;
this.collaborator.aroundAdviceTwo(this.name);
try {
ret = ((Integer)pjp.proceed()).intValue();
}
catch (Throwable t) {
throw new RuntimeException(t);
}
this.collaborator.aroundAdviceTwo(this.name);
return ret;
}
public void afterAdviceOne() {
this.collaborator.afterAdviceOne(this.name);
}
public void afterAdviceTwo() {
this.collaborator.afterAdviceTwo(this.name);
}
public interface Collaborator {
void beforeAdviceOne(String beanName);
void beforeAdviceTwo(String beanName);
void aroundAdviceOne(String beanName);
void aroundAdviceTwo(String beanName);
void afterAdviceOne(String beanName);
void afterAdviceTwo(String beanName);
}
}
class SimpleSpringBeforeAdvice implements MethodBeforeAdvice, BeanNameAware {
private PrecedenceTestAspect.Collaborator collaborator;
private String name;
/* (non-Javadoc)
* @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
this.collaborator.beforeAdviceOne(this.name);
}
public void setCollaborator(PrecedenceTestAspect.Collaborator collaborator) {
this.collaborator = collaborator;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
*/
@Override
public void setBeanName(String name) {
this.name = name;
}
}