package org.fishwife.jrugged.spring.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import com.google.common.base.Strings;
@Aspect
public class RetryTemplateAspect implements BeanFactoryAware {
private static final Logger logger =
LoggerFactory.getLogger(RetryTemplateAspect.class);
private BeanFactory beanFactory;
/** Default constructor. */
public RetryTemplateAspect() {
}
@Autowired
@Required
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/** Runs a method call through the spring managed
* {@link org.springframework.retry.support.RetryTemplate} instance indicated
* by the annotations "name" attribute.
*
* @param pjp a {@link org.aspectj.lang.ProceedingJoinPoint} representing an annotated
* method call.
* @param retryTemplateAnnotation the {@link org.fishwife.jrugged.spring.aspects.RetryTemplate} annotation
* that wrapped the method.
* @throws Throwable if the method invocation itself or the wrapping
* {@link org.springframework.retry.support.RetryTemplate} throws one during execution.
* @return The return value from the method call.
*/
@Around("@annotation(retryTemplateAnnotation)")
public Object retry(final ProceedingJoinPoint pjp,
final RetryTemplate retryTemplateAnnotation) throws Throwable {
final String name = retryTemplateAnnotation.name();
final String recoveryCallbackName = retryTemplateAnnotation.recoveryCallbackName();
org.springframework.retry.support.RetryTemplate retryTemplate =
beanFactory.getBean(name, org.springframework.retry.support.RetryTemplate.class);
RecoveryCallback<Object> recoveryCallback = null;
if (! Strings.isNullOrEmpty(recoveryCallbackName)) {
recoveryCallback =
beanFactory.getBean(recoveryCallbackName, org.springframework.retry.RecoveryCallback.class);
}
if (logger.isDebugEnabled()) {
logger.debug("Have @RetryTemplate method with retryTemplate name {} and callback name {}, " +
"wrapping call on method {} of target object {}",
new Object[]{
name,
recoveryCallbackName,
pjp.getSignature().getName(),
pjp.getTarget()});
}
return retryTemplate.execute(
new RetryCallback<Object, Exception>() {
public Object doWithRetry(RetryContext context) throws Exception {
try {
return pjp.proceed();
}
catch (Error e) {
throw e;
}
catch (Exception e) {
throw e;
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
},
recoveryCallback);
}
}