1+ /*
2+ * Copyright (c) 2024, Shelson Ferrari
3+ *
4+ * Licensed under the MIT License and the Apache License, Version 2.0 (the "Licenses"); you may not use this file except in
5+ * compliance with the Licenses. You may obtain a copy of the Licenses at
6+ *
7+ * MIT License:
8+ * https://opensource.org/licenses/MIT
9+ *
10+ * Apache License, Version 2.0:
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing, software distributed under the Licenses is
14+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
15+ * the Licenses for the specific language governing permissions and limitations under the Licenses.
16+ */
117package com .shelson .application .service ;
218
3- import org .apache .camel .ProducerTemplate ;
4- import org .springframework .beans .factory .annotation .Autowired ;
5- import org .springframework .stereotype .Service ;
6-
719import java .time .LocalDateTime ;
820import java .util .Map ;
921
22+ import org .slf4j .Logger ;
23+ import org .slf4j .LoggerFactory ;
24+ import org .springframework .beans .factory .annotation .Autowired ;
25+ import org .springframework .stereotype .Service ;
26+ import org .springframework .web .client .HttpClientErrorException ;
27+ import org .springframework .web .client .HttpServerErrorException ;
28+ import org .springframework .web .client .RestTemplate ;
29+
1030import com .shelson .application .dto .CurrencyConversionDTO ;
1131import com .shelson .domain .model .Currency ;
1232import com .shelson .domain .model .CurrencyConversion ;
1333import com .shelson .domain .repository .CurrencyConversionRepository ;
1434import com .shelson .infrastructure .exception .BusinessException ;
1535import com .shelson .infrastructure .exception .ResourceNotFoundException ;
1636
37+ /**
38+ * Service responsible for currency conversion operations.
39+ */
1740@ Service
1841public class CurrencyConversionService {
1942
2043 @ Autowired
21- private ProducerTemplate producerTemplate ;
44+ private RestTemplate restTemplate ;
2245
2346 @ Autowired
2447 private CurrencyConversionRepository repository ;
48+
49+ private static final Logger logger = LoggerFactory .getLogger (CurrencyConversionService .class );
2550
51+ /**
52+ * Converts an amount from a source currency to a target currency.
53+ *
54+ * @param sourceCurrency The source currency.
55+ * @param targetCurrency The target currency.
56+ * @param amount The amount to be converted.
57+ * @return A {@link CurrencyConversionDTO} containing the conversion details.
58+ * @throws BusinessException if the source or target currency is null, or if the amount is less than or equal to zero.
59+ * @throws ResourceNotFoundException if an error occurs when fetching exchange rates from the API, or if the target currency is invalid.
60+ */
2661 public CurrencyConversionDTO convertCurrency (Currency sourceCurrency , Currency targetCurrency , double amount ) throws BusinessException {
2762 if (sourceCurrency == null || targetCurrency == null ) {
2863 throw new BusinessException ("Source and target currencies must not be null" );
@@ -32,23 +67,21 @@ public CurrencyConversionDTO convertCurrency(Currency sourceCurrency, Currency t
3267 throw new BusinessException ("Amount must be greater than zero" );
3368 }
3469
35- Map <String , Object > headers = Map .of (
36- "sourceCurrency" , sourceCurrency .getCode (),
37- "targetCurrency" , targetCurrency .getCode ()
38- );
70+ logger .info ("Starting currency conversion from {} to {}" , sourceCurrency , targetCurrency );
3971
40- Map <String , Double > rates ;
72+ String apiUrl = "https://api.exchangerate-api.com/v4/latest/" + sourceCurrency .getCode ();
73+ ApiResponse response ;
4174 try {
42- rates = producerTemplate . requestBodyAndHeaders ( "direct:fetchRate" , null , headers , Map .class );
43- } catch (Exception e ) {
44- throw new ResourceNotFoundException ("Unable to fetch exchange rates from API" );
75+ response = restTemplate . getForObject ( apiUrl , ApiResponse .class );
76+ } catch (HttpClientErrorException | HttpServerErrorException ex ) {
77+ throw new ResourceNotFoundException ("Error fetching exchange rates from API: " + ex . getMessage () );
4578 }
4679
47- if (rates == null || rates . isEmpty () ) {
80+ if (response == null || response . getRates () == null ) {
4881 throw new ResourceNotFoundException ("Unable to fetch exchange rates from API" );
4982 }
5083
51- Double rate = rates .get (targetCurrency .getCode ());
84+ Double rate = response . getRates () .get (targetCurrency .getCode ());
5285
5386 if (rate == null ) {
5487 throw new ResourceNotFoundException ("Invalid target currency" );
@@ -58,6 +91,33 @@ public CurrencyConversionDTO convertCurrency(Currency sourceCurrency, Currency t
5891 CurrencyConversion conversion = new CurrencyConversion (sourceCurrency , targetCurrency , rate , LocalDateTime .now ());
5992 repository .save (conversion );
6093
94+ logger .info ("Conversion completed successfully" );
95+
6196 return new CurrencyConversionDTO (sourceCurrency , targetCurrency , rate , LocalDateTime .now (), amount , convertedAmount );
6297 }
98+
99+ /**
100+ * Inner class representing the exchange rates API response.
101+ */
102+ public static class ApiResponse {
103+ private Map <String , Double > rates ;
104+
105+ /**
106+ * Gets the exchange rates.
107+ *
108+ * @return A map where the keys are currency codes and the values are exchange rates.
109+ */
110+ public Map <String , Double > getRates () {
111+ return rates ;
112+ }
113+
114+ /**
115+ * Sets the exchange rates.
116+ *
117+ * @param rates A map where the keys are currency codes and the values are exchange rates.
118+ */
119+ public void setRates (Map <String , Double > rates ) {
120+ this .rates = rates ;
121+ }
122+ }
63123}
0 commit comments