/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.spring.aop;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.service.RetryAcceptor;
import com.liferay.portal.kernel.spring.aop.Property;
import com.liferay.portal.kernel.spring.aop.Retry;
import com.liferay.portal.util.PropsValues;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author Matthew Tambara
*/
public class RetryAdvice extends AnnotationChainableMethodAdvice<Retry> {
@Override
public Retry getNullAnnotation() {
return _nullRetry;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Retry retry = findAnnotation(methodInvocation);
if (retry == _nullRetry) {
return methodInvocation.proceed();
}
int retries = retry.retries();
if (retries < 0) {
retries = PropsValues.RETRY_ADVICE_MAX_RETRIES;
}
int totalRetries = retries;
if (retries >= 0) {
retries++;
}
Map<String, String> properties = new HashMap<>();
for (Property property : retry.properties()) {
properties.put(property.name(), property.value());
}
Class<? extends RetryAcceptor> clazz = retry.acceptor();
RetryAcceptor retryAcceptor = clazz.newInstance();
ServiceBeanMethodInvocation serviceBeanMethodInvocation =
(ServiceBeanMethodInvocation)methodInvocation;
serviceBeanMethodInvocation.mark();
Object returnValue = null;
Throwable throwable = null;
while ((retries < 0) || (retries-- > 0)) {
try {
returnValue = serviceBeanMethodInvocation.proceed();
if (!retryAcceptor.acceptResult(returnValue, properties)) {
return returnValue;
}
if (_log.isWarnEnabled() && (retries != 0)) {
String number = String.valueOf(retries);
if (retries < 0) {
number = "unlimited";
}
_log.warn(
"Retry on " + methodInvocation + " for " + number +
" more times due to result " + returnValue);
}
}
catch (Throwable t) {
throwable = t;
if (!retryAcceptor.acceptException(t, properties)) {
throw t;
}
if (_log.isWarnEnabled() && (retries != 0)) {
String number = String.valueOf(retries);
if (retries < 0) {
number = "unlimited";
}
_log.warn(
"Retry on " + methodInvocation + " for " + number +
" more times due to exception " + throwable,
throwable);
}
}
serviceBeanMethodInvocation.reset();
}
if (throwable != null) {
if (_log.isWarnEnabled()) {
_log.warn(
"Give up retrying on " + methodInvocation + " after " +
totalRetries + " retries and rethrow last retry's " +
"exception " + throwable,
throwable);
}
throw throwable;
}
if (_log.isWarnEnabled()) {
_log.warn(
"Give up retrying on " + methodInvocation + " after " +
totalRetries + " retries and returning the last retry's " +
"result " + returnValue);
}
return returnValue;
}
private static final Log _log = LogFactoryUtil.getLog(RetryAdvice.class);
private static final Retry _nullRetry = new Retry() {
@Override
public Class<? extends RetryAcceptor> acceptor() {
return null;
}
@Override
public Class<? extends Annotation> annotationType() {
return Retry.class;
}
@Override
public Property[] properties() {
return null;
}
@Override
public int retries() {
return 0;
}
};
}