Closed basarito closed 1 year ago
Well in my impression isAvailable()
checks if a certain provider is part of the conversion.default-chain
so in this example it would be false for IMF, but true for the mentioned ECB providers.
Yes, that's the case, ExchangeRateProvider has a default method isAvailable()
Checks if an {@link ExchangeRate} between two {@link CurrencyUnit} is available from this provider. This method should check, if a given rate is <i>currently</i> defined.
It is unrelated to any date or time. "defined" means as I hinted above that it is declared in the configuration.
Will close this, as it works as designed.
Feel free to create an enhancement request to try use the ProviderContext
and analyze it for certain aspects like the days, but I don't think it is realistic before a new JSR version (.Next) so try to set the milestone accordingly if you can.
Ok, but in this case for org.javamoney.moneta.spi.CompoundRateProvider#getExchangeRate
, if isAvailable
just checks the presence in the chain,getExchangeRate
is bound to fail for some providers. Why does it re-throw CurrencyConversionException
and not give the next provider in the chain a chance to return an ExchangeRate
?
The final exception message also doesn't make sense because All delegate providers failed to deliver rate
isn't quite true, 'cause not all providers tried to deliver rate, if another one failed before their turn.
Maybe @fprochazka remembers why he added that "fail early" exception instead of looping to another provider. I'm afraid, Anatole, the main author of the class is no longer available since he got lost in a QAnon rabbit hole some while ago...
Let's see, what @fprochazka might say and if he thinks there could be a different solution, but either way this would have to be an improvement for Moneta 1.5 or even a 2.x release. If he agrees it could skip the exception or somehow "cache" it (because throwing it there preserves the information, but maybe one could find some special treatment if the chain is not empty yet) feel free to reopen it then, but for now let's wait for his input.
I wanted the entire operation (the business operation that is calling the exchange rates) to fail if one of the delegate providers threw an error because I've implemented a bunch of completely custom providers that sometimes could throw an exception if they failed for some critical reason (I've had e.g. database provider and if there were the table missing, it would rightfully throw a pretty critical exception)
The problem is that the CompoundRateProvider
catches every exception. If you want to allow controlling the code flow using exceptions, there should be a clear distinction between exceptions that should kill the operation/app (missing table, something other that is completely broken and should sound all the alerts in a live system) and exceptions that can be silenced (rates for a given day are missing, but loading and processing them worked correctly)
@fprochazka but in that case isAvailable
needs to do a different kind of check or have getExchangeRate
always return null
for non-critical failures.. the way it is at the moment, there's no way to chain providers and attempt several ones until you get one to return a result, and I think that kind of beats the purpose of a provider chain and CompoundRateProvider
in general
I don't think it beats the purpose, the problem is that the CompoundRateProvider
is expected to do different things when it should do fewer things. This entire mechanism should be reworked and configured by code, not a single stringy property.
The problem starts with the fact, that the library as a whole doesn't have a very good definition of how to work with error states.
Hello, I'm not sure if I've misunderstood how this works, but I'm trying to get exchange rate on a given date (which can be current or historic) and I'm following the suggestion from the docs of
ECBHistoricRateProvider
/ECBHistoric90RateProvider
:The default chain is defined like:
conversion.default-chain=IDENT,ECB,ECB-HIST90,ECB-HIST
I would assume that this means that
provider.getCurrencyConversion(conversionQuery)
would attempt each provider in the chain and move on if noCurrencyConversion
is available.However, looking a bit into the source code, I see that the
localDate
that gets set on the query isn't even inspected when searching for available providers. AlsoisAvailable
method (javax.money.convert.ExchangeRateProvider#isAvailable(javax.money.convert.ConversionQuery)
) doesn't really do what is expected, and as a result this error gets thrown:for this query:
Basically
ECB
is the first one to try conversion and fails instantly because, as expected, it doesn't have data for historic date2022-01-03
.My questions are:
ECB
provider flagged as available in the first place?ECB-HIST90
and attempt conversion there?Version:
1.4.2