2323import org .apache .camel .ProducerTemplate ;
2424import org .slf4j .Logger ;
2525import org .slf4j .LoggerFactory ;
26- import org .springframework .beans .factory .annotation .Autowired ;
2726import org .springframework .stereotype .Service ;
2827
2928import com .fasterxml .jackson .core .type .TypeReference ;
3635import com .shelson .infrastructure .exception .ResourceNotFoundException ;
3736
3837/**
39- * Camel route for handling currency conversion requests.
40- * This route takes the source currency, target currency, and amount as headers,
41- * processes the conversion using the {@link CurrencyConversionService}, and returns the conversion details.
38+ * Service responsible for handling currency conversion requests using Apache Camel.
39+ * This service takes the source currency, target currency, and amount as parameters,
40+ * performs the currency conversion, and returns the conversion details as a DTO.
41+ *
42+ * <p>This service uses Apache Camel's {@link ProducerTemplate} to request exchange rates and
43+ * interacts with the {@link CurrencyConversionRepository} to persist conversion records.
4244 *
4345 * @version 0.6.3
4446 * @since 2024-07-24
4547 *
4648 * @author Shelson Ferrari
4749 *
4850 * @see com.shelson.application.dto.CurrencyConversionDTO
49- * @see com.shelson.application.service.CurrencyConversionService
50- * @see com.shelson.application.processors.ExchangeRateProcessor
51- * @see org.apache.camel.ProducerTemplate
5251 * @see com.shelson.domain.model.Currency
52+ * @see com.shelson.domain.model.CurrencyConversion
53+ * @see com.shelson.domain.repository.CurrencyConversionRepository
54+ * @see com.shelson.infrastructure.exception.BusinessException
55+ * @see com.shelson.infrastructure.exception.ResourceNotFoundException
56+ * @see org.apache.camel.ProducerTemplate
5357 */
5458@ Service
5559public class CurrencyConversionService {
5660
57- @ Autowired
58- private ProducerTemplate producerTemplate ;
59-
60- @ Autowired
61- private CurrencyConversionRepository repository ;
61+ private final ProducerTemplate producerTemplate ;
62+ private final CurrencyConversionRepository repository ;
63+ private final ObjectMapper objectMapper ;
6264
6365 private static final Logger logger = LoggerFactory .getLogger (CurrencyConversionService .class );
6466
65- private final ObjectMapper objectMapper = new ObjectMapper ();
66-
67+ /**
68+ * Constructs a {@code CurrencyConversionService} with the specified dependencies.
69+ *
70+ * @param producerTemplate The Apache Camel {@link ProducerTemplate} used to request exchange rates.
71+ * @param repository The {@link CurrencyConversionRepository} used to save currency conversion records.
72+ * @param objectMapper The {@link ObjectMapper} used to parse and convert JSON data.
73+ */
74+ public CurrencyConversionService (ProducerTemplate producerTemplate ,
75+ CurrencyConversionRepository repository ,
76+ ObjectMapper objectMapper ) {
77+ this .producerTemplate = producerTemplate ;
78+ this .repository = repository ;
79+ this .objectMapper = objectMapper ;
80+ }
81+
6782 /**
6883 * Converts the given amount from the source currency to the target currency.
6984 *
@@ -77,6 +92,25 @@ public class CurrencyConversionService {
7792 public CurrencyConversionDTO convertCurrency (Currency sourceCurrency , Currency targetCurrency , double amount ) {
7893 logger .info ("Starting currency conversion: source={}, target={}, amount={}" , sourceCurrency , targetCurrency , amount );
7994
95+ validateInputs (sourceCurrency , targetCurrency , amount );
96+ Map <String , Double > rates = fetchExchangeRates (sourceCurrency );
97+
98+ Double rate = getRateForTargetCurrency (rates , targetCurrency );
99+ double convertedAmount = calculateConvertedAmount (amount , rate );
100+
101+ CurrencyConversion conversion = saveCurrencyConversion (sourceCurrency , targetCurrency , rate );
102+ return buildCurrencyConversionDTO (sourceCurrency , targetCurrency , amount , convertedAmount , conversion );
103+ }
104+
105+ /**
106+ * Validates the input parameters for currency conversion.
107+ *
108+ * @param sourceCurrency The source {@link Currency} to convert from.
109+ * @param targetCurrency The target {@link Currency} to convert to.
110+ * @param amount The amount to be converted.
111+ * @throws BusinessException if sourceCurrency or targetCurrency is null, or if the amount is less than or equal to zero.
112+ */
113+ private void validateInputs (Currency sourceCurrency , Currency targetCurrency , double amount ) {
80114 if (sourceCurrency == null || targetCurrency == null ) {
81115 logger .error ("Source or target currency is null" );
82116 throw new BusinessException ("Source and target currencies must not be null" );
@@ -85,31 +119,82 @@ public CurrencyConversionDTO convertCurrency(Currency sourceCurrency, Currency t
85119 logger .error ("Invalid amount: {}" , amount );
86120 throw new BusinessException ("Amount must be greater than zero" );
87121 }
122+ }
88123
89- Map <String , Double > rates = null ;
124+ /**
125+ * Fetches exchange rates from an external service.
126+ *
127+ * @param sourceCurrency The source {@link Currency} for which the exchange rates are requested.
128+ * @return A {@link Map} containing the exchange rates, where the keys are currency codes and the values are rates.
129+ * @throws ResourceNotFoundException if an error occurs while fetching the exchange rates.
130+ */
131+ private Map <String , Double > fetchExchangeRates (Currency sourceCurrency ) {
90132 try {
91133 Object response = producerTemplate .requestBodyAndHeader ("direct:fetchRate" , null , "sourceCurrency" , sourceCurrency .getCode ());
92134 if (response != null ) {
93- rates = objectMapper .convertValue (response , new TypeReference <Map <String , Double >>() {});
94- logger .info ("Fetched exchange rates: {}" , rates );
135+ return objectMapper .convertValue (response , new TypeReference <Map <String , Double >>() {});
95136 }
96137 } catch (Exception ex ) {
97138 logger .error ("Error fetching exchange rates from API: {}" , ex .getMessage ());
98139 throw new ResourceNotFoundException ("Error fetching exchange rates from API" , ex );
99140 }
141+ return null ;
142+ }
100143
144+ /**
145+ * Retrieves the exchange rate for the target currency from the fetched rates.
146+ *
147+ * @param rates A {@link Map} containing the exchange rates.
148+ * @param targetCurrency The target {@link Currency} for which the rate is needed.
149+ * @return The exchange rate for the target currency.
150+ * @throws BusinessException if the target currency rate is invalid or missing.
151+ */
152+ private Double getRateForTargetCurrency (Map <String , Double > rates , Currency targetCurrency ) {
101153 if (rates == null || !rates .containsKey (targetCurrency .getCode ())) {
102154 logger .error ("Invalid or missing target currency rate: {}" , targetCurrency );
103155 throw new BusinessException ("Invalid or missing target currency rate" );
104156 }
157+ return rates .get (targetCurrency .getCode ());
158+ }
105159
106- Double rate = rates .get (targetCurrency .getCode ());
107- double convertedAmount = amount * rate ;
160+ /**
161+ * Calculates the converted amount based on the given amount and exchange rate.
162+ *
163+ * @param amount The amount to be converted.
164+ * @param rate The exchange rate to be used for conversion.
165+ * @return The converted amount.
166+ */
167+ private double calculateConvertedAmount (double amount , Double rate ) {
168+ return amount * rate ;
169+ }
170+
171+ /**
172+ * Saves the currency conversion record to the repository.
173+ *
174+ * @param sourceCurrency The source {@link Currency}.
175+ * @param targetCurrency The target {@link Currency}.
176+ * @param rate The exchange rate used for conversion.
177+ * @return The {@link CurrencyConversion} record that was saved.
178+ */
179+ private CurrencyConversion saveCurrencyConversion (Currency sourceCurrency , Currency targetCurrency , Double rate ) {
108180 CurrencyConversion conversion = new CurrencyConversion (sourceCurrency , targetCurrency , rate , LocalDateTime .now ());
109181 repository .save (conversion );
110182 logger .info ("Currency conversion saved: {}" , conversion );
183+ return conversion ;
184+ }
111185
112- CurrencyConversionDTO result = new CurrencyConversionDTO (sourceCurrency , targetCurrency , rate , LocalDateTime .now (), amount , convertedAmount );
186+ /**
187+ * Builds a {@link CurrencyConversionDTO} with the conversion details.
188+ *
189+ * @param sourceCurrency The source {@link Currency}.
190+ * @param targetCurrency The target {@link Currency}.
191+ * @param amount The amount to be converted.
192+ * @param convertedAmount The result of the conversion.
193+ * @param conversion The {@link CurrencyConversion} record used for creating the DTO.
194+ * @return A {@link CurrencyConversionDTO} containing the conversion details.
195+ */
196+ private CurrencyConversionDTO buildCurrencyConversionDTO (Currency sourceCurrency , Currency targetCurrency , double amount , double convertedAmount , CurrencyConversion conversion ) {
197+ CurrencyConversionDTO result = new CurrencyConversionDTO (sourceCurrency , targetCurrency , conversion .getConversionRate (), conversion .getQueryDate (), amount , convertedAmount );
113198 logger .info ("Conversion result: {}" , result );
114199 return result ;
115200 }
0 commit comments