Skip to content

Commit 9b01e60

Browse files
committed
Add retry mechanism to CompoundRateProvider.getExchangeRate on failure
Modified the getExchangeRate method in the CompoundRateProvider class to introduce a failFast parameter. Previously, the method would immediately throw an exception on the first provider failure. This change allows for a more flexible approach by adding an option to continue attempting to get an exchange rate from subsequent providers if failFast is set to false. - Added a new overloaded getExchangeRate method with a failFast boolean parameter. - If failFast is true, the method retains the original behavior of failing immediately on the first exception. - If failFast is false, the method logs a warning and continues to the next provider in case of an exception. This update addresses some of the limitations described in issue #385.
1 parent a61917b commit 9b01e60

File tree

3 files changed

+89
-6
lines changed

3 files changed

+89
-6
lines changed

moneta-core/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@
216216
</dependencyManagement>
217217

218218
<dependencies>
219+
<dependency>
220+
<groupId>org.javamoney</groupId>
221+
<artifactId>moneta</artifactId>
222+
<version>1.4.4</version>
223+
<type>pom</type>
224+
<scope>test</scope>
225+
</dependency>
219226
<dependency>
220227
<groupId>javax.money</groupId>
221228
<artifactId>money-api</artifactId>

moneta-core/src/main/java/org/javamoney/moneta/spi/CompoundRateProvider.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Objects;
2929
import java.util.Optional;
3030
import java.util.Set;
31+
import java.util.logging.Logger;
3132

3233
/**
3334
* This class implements a {@link ExchangeRateProvider} that delegates calls to
@@ -48,6 +49,8 @@ public class CompoundRateProvider extends AbstractRateProvider {
4849
*/
4950
private final List<ExchangeRateProvider> providers = new ArrayList<>();
5051

52+
private static final Logger logger = Logger.getLogger(CompoundRateProvider.class.getName());
53+
5154
/**
5255
* Constructor.
5356
*
@@ -102,6 +105,10 @@ private void addProvider(ExchangeRateProvider prov) {
102105
*/
103106
@Override
104107
public ExchangeRate getExchangeRate(ConversionQuery conversionQuery) {
108+
return getExchangeRate(conversionQuery, false);
109+
}
110+
111+
public ExchangeRate getExchangeRate(ConversionQuery conversionQuery, boolean failFast) {
105112
for (ExchangeRateProvider prov : this.providers) {
106113
try {
107114
if (prov.isAvailable(conversionQuery)) {
@@ -111,15 +118,18 @@ public ExchangeRate getExchangeRate(ConversionQuery conversionQuery) {
111118
}
112119
}
113120
} catch (Exception e) {
114-
throw new CurrencyConversionException(conversionQuery.getBaseCurrency(), conversionQuery.getCurrency(), null,
115-
"Rate Provider did not return data though at check before data was flagged as available," +
116-
" provider=" + prov.getContext().getProviderName() + ", query=" + conversionQuery, e);
121+
if (failFast) {
122+
throw new CurrencyConversionException(conversionQuery.getBaseCurrency(), conversionQuery.getCurrency(), null,
123+
"Rate Provider did not return data though at check before data was flagged as available," +
124+
" provider=" + prov.getContext().getProviderName() + ", query=" + conversionQuery, e);
125+
} else {
126+
logger.warning("Rate Provider did not return data though at check before data was flagged as available," +
127+
" provider=" + prov.getContext().getProviderName() + ", query=" + conversionQuery + ", error=" + e.getMessage());
128+
}
117129
}
118130
}
119131
throw new CurrencyConversionException(conversionQuery.getBaseCurrency(), conversionQuery.getCurrency(), null,
120132
"All delegate providers failed to deliver rate, providers=" + this.providers +
121133
", query=" + conversionQuery);
122134
}
123-
124-
125-
}
135+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.javamoney.moneta.spi;
2+
3+
import org.testng.annotations.Test;
4+
5+
import javax.money.convert.*;
6+
7+
import java.time.DayOfWeek;
8+
import java.time.LocalDate;
9+
import java.time.temporal.TemporalAdjusters;
10+
11+
import static org.testng.Assert.*;
12+
13+
public class CompoundRateProviderTest {
14+
15+
@Test
16+
public void testGetExchangeRate() {
17+
String baseCurrency = "EUR";
18+
String termCurrency = "GBP";
19+
LocalDate date = lastWeekTuesday();
20+
ConversionQuery conversionQuery = ConversionQueryBuilder.of()
21+
.setBaseCurrency(baseCurrency)
22+
.setTermCurrency(termCurrency)
23+
.set(date)
24+
.build();
25+
26+
ExchangeRateProvider compoundRateProvider = MonetaryConversions.getExchangeRateProvider("ECB", "ECB-HIST90");
27+
assertNotNull(compoundRateProvider.getExchangeRate(conversionQuery));
28+
}
29+
30+
@Test
31+
public void testGetExchangeRateAllProvidersFail() {
32+
String baseCurrency = "EUR";
33+
String termCurrency = "GBP";
34+
LocalDate date = lastWeekTuesday();
35+
ConversionQuery conversionQuery = ConversionQueryBuilder.of()
36+
.setBaseCurrency(baseCurrency)
37+
.setTermCurrency(termCurrency)
38+
.set(date)
39+
.build();
40+
41+
ExchangeRateProvider compoundRateProvider = MonetaryConversions.getExchangeRateProvider("ECB", "IMF");
42+
assertThrows(CurrencyConversionException.class, () -> compoundRateProvider.getExchangeRate(conversionQuery));
43+
}
44+
45+
@Test
46+
public void testGetExchangeRateFailingFast() {
47+
String baseCurrency = "EUR";
48+
String termCurrency = "GBP";
49+
LocalDate date = lastWeekTuesday();
50+
ConversionQuery conversionQuery = ConversionQueryBuilder.of()
51+
.setBaseCurrency(baseCurrency)
52+
.setTermCurrency(termCurrency)
53+
.set(date)
54+
.build();
55+
56+
// Need to cast to CompoundRateProvider to access the getExchangeRate method that takes a boolean parameter
57+
CompoundRateProvider compoundRateProvider = (CompoundRateProvider) MonetaryConversions.getExchangeRateProvider("ECB", "ECB-HIST90");
58+
assertThrows(CurrencyConversionException.class, () -> compoundRateProvider.getExchangeRate(conversionQuery, true));
59+
}
60+
61+
private LocalDate lastWeekTuesday() {
62+
LocalDate today = LocalDate.now();
63+
LocalDate lastTuesday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.TUESDAY));
64+
return lastTuesday.minusWeeks(1);
65+
}
66+
}

0 commit comments

Comments
 (0)