Skip to content
Snippets Groups Projects
Commit 16adca5d authored by Filip Piták's avatar Filip Piták
Browse files

Add implementation for Exchange rates from public API

parent 7f8fcaea
No related branches found
No related tags found
No related merge requests found
Showing
with 123 additions and 47 deletions
package cz.muni.pa165.banking.application.configuration;
import cz.muni.pa165.banking.domain.money.exchange.ExchangeRateService;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Currency;
import java.util.List;
@Component
public class ExchangeRateInitializer {
private final Logger logger = LoggerFactory.getLogger(ExchangeRateInitializer.class);
private final ExchangeRateService exchangeRateService;
@Value("#{'${banking.apps.rates.initial.currencies}'.split(',')}")
private List<String> currencies;
public ExchangeRateInitializer(ExchangeRateService exchangeRateService) {
this.exchangeRateService = exchangeRateService;
}
@PostConstruct
void initialize() {
for (String currency : currencies) {
try {
// ignore result, just call service to trigger mechanism to cache data
exchangeRateService.getRate(Currency.getInstance(currency), Currency.getInstance(currency));
} catch (Exception e) {
logger.warn(String.format("Initializing exchange rates for %s failed. API might be unavailable!", currency));
}
}
}
}
......@@ -3,13 +3,10 @@ package cz.muni.pa165.banking.application.messaging;
import com.fasterxml.jackson.databind.ObjectMapper;
import cz.muni.pa165.banking.domain.messaging.MessageProducer;
import cz.muni.pa165.banking.domain.messaging.ProcessRequest;
import cz.muni.pa165.banking.domain.transaction.TransactionType;
import cz.muni.pa165.banking.exception.ServerError;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.UUID;
@Service
public class ProcessProducer implements MessageProducer {
......@@ -22,12 +19,6 @@ public class ProcessProducer implements MessageProducer {
this.messagingService = messagingService;
this.mapper = mapper;
}
@PostConstruct
void testing() {
ProcessRequest data = new ProcessRequest(UUID.randomUUID(), TransactionType.DEPOSIT);
send(data);
}
@Override
public void send(ProcessRequest data) {
......
package cz.muni.pa165.banking.application.proxy;
import cz.muni.pa165.banking.account.query.CustomerServiceApi;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Dummy {
@Autowired
private CustomerServiceApi customerServiceApi;
@PostConstruct
public void test() {
var jj = customerServiceApi.getBalance("id1");
System.out.println("jozo");
}
}
package cz.muni.pa165.banking.application.proxy;
// some proxy for a REST API, which contains real-time data about the currency rates
// e.g. https://exchangeratesapi.io/
// https://nordicapis.com/10-apis-for-currency-exchange-rates/
public interface ExchangeRatesApi {
// TODO nejake methods po vybere a nastudovani API
}
package cz.muni.pa165.banking.application.proxy.rate;
import cz.muni.pa165.banking.exception.UnexpectedValueException;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.HashMap;
import java.util.Map;
public class ExchangeRateResponseProcessor {
public static Map<Currency, BigDecimal> process(Map<String, Object> response) {
if (!response.get("result").equals("success")) {
throw new UnexpectedValueException("Exchange rate API unavailable");
}
Map<String, Object> rates = (Map<String, Object>) response.get("conversion_rates");
Map<Currency, BigDecimal> result = new HashMap<>();
for (String currencyCode : rates.keySet()) {
Currency currency;
try {
currency = Currency.getInstance(currencyCode);
} catch (Exception e) {
continue;
}
Object value = rates.get(currencyCode);
BigDecimal rate;
if (value instanceof Integer val) {
rate = BigDecimal.valueOf(val);
} else if (value instanceof Double val) {
rate = BigDecimal.valueOf(val);
} else {
String strVal = value.toString();
double val = Double.parseDouble(strVal);
rate = BigDecimal.valueOf(val);
}
result.put(currency, rate);
}
return result;
}
}
package cz.muni.pa165.banking.application.proxy.rate;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
// https://app.exchangerate-api.com
@FeignClient(name = "ExchangeRateApi", url = "${banking.apps.rates.url}")
public interface ExchangeRatesApi {
@GetMapping("/latest/{currency}")
Map<String, Object> getRatesOfCurrency(@RequestParam String currency);
}
package cz.muni.pa165.banking.application.service;
import cz.muni.pa165.banking.application.proxy.rate.ExchangeRateResponseProcessor;
import cz.muni.pa165.banking.application.proxy.rate.ExchangeRatesApi;
import cz.muni.pa165.banking.domain.money.exchange.ExchangeRateService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class ExchangeRateServiceImpl implements ExchangeRateService {
// TODO call external API containing current information about exchange rates -> Milestone2
// either actual API containing real data, or custom 'mock' API containing static data
// private final ExchangeRatesApi proxy;
private final ExchangeRatesApi exchangeRatesApi;
Map<Currency, Map<Currency, BigDecimal>> exchangeRates = new ConcurrentHashMap<>();
// public ExchangeRateServiceImpl(ExchangeRatesApi proxy) {
// this.proxy = proxy;
// }
public ExchangeRateServiceImpl(ExchangeRatesApi exchangeRatesApi) {
this.exchangeRatesApi = exchangeRatesApi;
}
@Override
public BigDecimal getRate(Currency base, Currency target) {
return BigDecimal.ONE;
if (!exchangeRates.containsKey(base)) {
Map<String, Object> response = exchangeRatesApi.getRatesOfCurrency(base.getCurrencyCode());
exchangeRates.put(base, ExchangeRateResponseProcessor.process(response));
}
return exchangeRates.get(base).get(target);
}
}
......@@ -11,6 +11,11 @@ banking:
host: localhost
port: 8081
url: ${banking.apps.query.host}:${banking.apps.query.port}
rates:
api-key: 5f40db3a892e886bda8a6967
url: https://v6.exchangerate-api.com/v6/${banking.apps.rates.api-key}
initial:
currencies: CZK, EUR, USD
spring:
application:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment