Skip to content

Commit 13408c9

Browse files
authored
Merge pull request #419 from sernamar/issue-385
Add retry mechanism to `CompoundRateProvider.getExchangeRate` on failure
2 parents 0f2dea3 + 8010b4a commit 13408c9

File tree

3 files changed

+90
-6
lines changed

3 files changed

+90
-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, true);
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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
// Need to cast to CompoundRateProvider to access the getExchangeRate method that takes a boolean parameter
27+
CompoundRateProvider compoundRateProvider = (CompoundRateProvider) MonetaryConversions.getExchangeRateProvider("ECB", "ECB-HIST90");
28+
assertNotNull(compoundRateProvider.getExchangeRate(conversionQuery, false));
29+
}
30+
31+
@Test
32+
public void testGetExchangeRateAllProvidersFail() {
33+
String baseCurrency = "EUR";
34+
String termCurrency = "GBP";
35+
LocalDate date = lastWeekTuesday();
36+
ConversionQuery conversionQuery = ConversionQueryBuilder.of()
37+
.setBaseCurrency(baseCurrency)
38+
.setTermCurrency(termCurrency)
39+
.set(date)
40+
.build();
41+
42+
// Need to cast to CompoundRateProvider to access the getExchangeRate method that takes a boolean parameter
43+
CompoundRateProvider compoundRateProvider = (CompoundRateProvider) MonetaryConversions.getExchangeRateProvider("ECB", "IMF");
44+
assertThrows(CurrencyConversionException.class, () -> compoundRateProvider.getExchangeRate(conversionQuery, false));
45+
}
46+
47+
@Test
48+
public void testGetExchangeRateFailingFast() {
49+
String baseCurrency = "EUR";
50+
String termCurrency = "GBP";
51+
LocalDate date = lastWeekTuesday();
52+
ConversionQuery conversionQuery = ConversionQueryBuilder.of()
53+
.setBaseCurrency(baseCurrency)
54+
.setTermCurrency(termCurrency)
55+
.set(date)
56+
.build();
57+
58+
ExchangeRateProvider compoundRateProvider = MonetaryConversions.getExchangeRateProvider("ECB", "ECB-HIST90");
59+
assertThrows(CurrencyConversionException.class, () -> compoundRateProvider.getExchangeRate(conversionQuery));
60+
}
61+
62+
private LocalDate lastWeekTuesday() {
63+
LocalDate today = LocalDate.now();
64+
LocalDate lastTuesday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.TUESDAY));
65+
return lastTuesday.minusWeeks(1);
66+
}
67+
}

0 commit comments

Comments
 (0)