/** * Access a {@link ExchangeRate} using the given currencies. The * {@link ExchangeRate} may be, depending on the data provider, eal-time or * deferred. This method should return the rate that is <i>currently</i> * valid. * * @param baseCode base currency code, not {@code null} * @param termCode term/target currency code, not {@code null} * @return the matching {@link ExchangeRate}. * @throws CurrencyConversionException If no such rate is available. * @throws MonetaryException if one of the currency codes passed is not valid. */ default ExchangeRate getExchangeRate(String baseCode, String termCode){ return getExchangeRate(Monetary.getCurrency(baseCode), Monetary.getCurrency(termCode)); }
@Override public ExchangeRate getExchangeRate(ConversionQuery conversionQuery) { for (ExchangeRateProvider prov : this.providers) { try { if (prov.isAvailable(conversionQuery)) { ExchangeRate rate = prov.getExchangeRate(conversionQuery); if (Objects.nonNull(rate)) { return rate; } } } catch (Exception e) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "Rate Provider did not return data though at check before data was flagged as available," + " provider=" + prov.getContext().getProviderName() + ", query=" + conversionQuery); } } throw new CurrencyConversionException(conversionQuery.getBaseCurrency(), conversionQuery.getCurrency(), null, "All delegate prov iders failed to deliver rate, providers=" + this.providers + ", query=" + conversionQuery); }
/** * Access a {@link CurrencyConversion} that can be applied as a * {@link MonetaryOperator} to an amount. * * @param termCode terminal/target currency code, not {@code null} * @return a new instance of a corresponding {@link CurrencyConversion}, * never {@code null}. * @throws MonetaryException if one of the currency codes passed is not valid. */ default CurrencyConversion getCurrencyConversion(String termCode){ return getCurrencyConversion(Monetary.getCurrency(termCode)); }
/** * The method reverses the {@link ExchangeRate} to a rate mapping from term * to base {@link CurrencyUnit}. Hereby the factor must <b>not</b> be * recalculated as {@code 1/oldFactor}, since typically reverse rates are * not symmetric in most cases. * * @return the matching reversed {@link ExchangeRate}, or {@code null}, if * the rate cannot be reversed. */ default ExchangeRate getReversed(ExchangeRate rate){ ConversionQuery reverseQuery = rate.getContext().toQueryBuilder().setBaseCurrency(rate.getCurrency()) .setTermCurrency(rate.getBaseCurrency()).build(); if(isAvailable(reverseQuery)){ return getExchangeRate(reverseQuery); } return null; }
private static ProviderContext createContext(Iterable<ExchangeRateProvider> providers) { Set<RateType> rateTypeSet = new HashSet<>(); StringBuilder providerName = new StringBuilder("Compound: "); List<ProviderContext> childContextList = new ArrayList<>(); for (ExchangeRateProvider exchangeRateProvider : providers) { childContextList.add(exchangeRateProvider.getContext()); providerName.append(exchangeRateProvider.getContext().getProviderName()); providerName.append(',' ); rateTypeSet.addAll(exchangeRateProvider.getContext().getRateTypes()); } providerName.setLength(providerName.length() - 1); ProviderContextBuilder builder = ProviderContextBuilder.of(providerName.toString(), rateTypeSet); builder.set(CHILD_PROVIDER_CONTEXTS_KEY, childContextList); return builder.build(); }
/** * 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. * * @param baseCode the base currency code * @param termCode the terminal/target currency code * @return {@code true}, if such an {@link ExchangeRate} is currently * defined. * @throws MonetaryException if one of the currency codes passed is not valid. */ default boolean isAvailable(String baseCode, String termCode){ return isAvailable(Monetary.getCurrency(baseCode), Monetary.getCurrency(termCode)); }
/** * 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. * * @param conversionQuery the required {@link ConversionQuery}, not {@code null} * @return {@code true}, if such an {@link ExchangeRate} is currently * defined. */ default boolean isAvailable(ConversionQuery conversionQuery){ Objects.requireNonNull(conversionQuery); try{ return conversionQuery.getProviderNames().isEmpty() || conversionQuery.getProviderNames().contains(getContext().getProviderName()); } catch(Exception e){ return false; } }
/** * 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. * * @param base the base {@link CurrencyUnit} * @param term the term {@link CurrencyUnit} * @return {@code true}, if such an {@link ExchangeRate} is currently * defined. */ default boolean isAvailable(CurrencyUnit base, CurrencyUnit term){ return isAvailable(ConversionQueryBuilder.of().setBaseCurrency(base).setTermCurrency(term).build()); }
/** * Access a {@link ExchangeRate} using the given currencies. The * {@link ExchangeRate} may be, depending on the data provider, eal-time or * deferred. This method should return the rate that is <i>currently</i> * valid. * * @param base base {@link CurrencyUnit}, not {@code null} * @param term term {@link CurrencyUnit}, not {@code null} * @throws CurrencyConversionException If no such rate is available. */ default ExchangeRate getExchangeRate(CurrencyUnit base, CurrencyUnit term){ Objects.requireNonNull(base, "Base Currency is null"); Objects.requireNonNull(term, "Term Currency is null"); return getExchangeRate(ConversionQueryBuilder.of().setBaseCurrency(base).setTermCurrency(term).build()); }
/** * Access an instance of {@link CurrencyConversion}. * * @param conversionQuery the {@link javax.money.convert.ConversionQuery} determining the type of conversion * required, not null. * @return the corresponding conversion, not null. * @throws javax.money.MonetaryException if no matching conversion could be found. * @see #isConversionAvailable(javax.money.convert.ConversionQuery) */ default CurrencyConversion getConversion(ConversionQuery conversionQuery) { return getExchangeRateProvider(conversionQuery).getCurrencyConversion( Objects.requireNonNull(conversionQuery.getCurrency(), "Terminating Currency is required.") ); }
/** * Test if all providers returns valid meta data. * * @see javax.money.convert.ProviderContext */ @Test(description = "4.3.1 Test if all ExchangeRateProvider instances returns valid ProviderContext.") @SpecAssertion(id = "431-A3", section = "4.3.1") public void testProviderMetadata() { for (String providerName : MonetaryConversions.getConversionProviderNames()) { ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerName); AssertJUnit.assertNotNull("Provider mot accessible: " + providerName, prov); ProviderContext ctx = prov.getContext(); AssertJUnit.assertNotNull( "ExchangeProvider must return a valid ProviderContext, but returned null: " + providerName, ctx); AssertJUnit.assertEquals("ExchangeProvider's ProviderContext returns invalid name: " + providerName, providerName, ctx.getProviderName()); AssertJUnit.assertNotNull( "ExchangeProvider's ProviderContext declares invalid RateTypes to be returned (null): " + providerName, ctx.getRateTypes()); AssertJUnit.assertFalse( "ExchangeProvider's ProviderContext declares empty RateTypes to be returned: " + providerName, ctx.getRateTypes().isEmpty()); } }
/** * Bad case: try accessing rates with inconsistent/invalid data.<p> * Hint: this assertion will require multiple tests to be written! */ @Test(description = "4.3.3 Bad case: try accessing exchange rates with null term currency code.") @SpecAssertion(id = "433-A3", section = "4.3.3") public void testInvalidUsage_NullTargetCurrency() { for (String providerID : MonetaryConversions.getConversionProviderNames()) { if ("TestRateProvider".equals(providerID)) { continue; } ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID); try { prov.getExchangeRate("CHF", null); Assert.fail("ExchangeRateProvider should throw NullPointerException when an null target currency " + "is passed to getExchangeRate(String,String), provider: " + providerID); } catch (NullPointerException e) { // OK } } }
/** * Access a {@link CurrencyConversion} that can be applied as a * {@link MonetaryOperator} to an amount. * * @param term term {@link CurrencyUnit}, not {@code null} * @return a new instance of a corresponding {@link CurrencyConversion}, * never {@code null}. */ default CurrencyConversion getCurrencyConversion(CurrencyUnit term){ return getCurrencyConversion(ConversionQueryBuilder.of().setTermCurrency(term).build()); }
/** * Bad case: try accessing rates with inconsistent/invalid data.<p> * Hint: this assertion will require multiple tests to be written! */ @Test(description = "4.3.3 Bad case: try accessing exchange rates with null base currency code.") @SpecAssertion(id = "433-A3", section = "4.3.3") public void testInvalidUsage_NullSourceCurrency() { for (String providerID : MonetaryConversions.getConversionProviderNames()) { if ("TestRateProvider".equals(providerID)) { continue; } ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID); try { prov.getExchangeRate(null, "CHF"); Assert.fail("ExchangeRateProvider should throw NullPointerException when an null source currency " + "is passed to getExchangeRate(String,String), provider: " + providerID); } catch (NullPointerException e) { // OK } } }
public static void main(String[] args) { ExchangeRateProvider imfRateProvider = MonetaryConversions .getExchangeRateProvider("IMF"); ExchangeRateProvider ecbRateProvider = MonetaryConversions .getExchangeRateProvider("ECB"); CurrencyUnit real = Monetary.getCurrency("BRL"); CurrencyUnit dollar = Monetary.getCurrency(Locale.US); CurrencyConversion ecbDollarConvertion = ecbRateProvider .getCurrencyConversion(dollar); CurrencyConversion imfDollarConvertion = imfRateProvider .getCurrencyConversion(dollar); MonetaryAmount money = Money.of(10, real); System.out.println(money.with(ecbDollarConvertion)); System.out.println(money.with(imfDollarConvertion)); }
/** * Bad case: try accessing rates with inconsistent/invalid data.<p> * Hint: this assertion will require multiple tests to be written! */ @Test(description = "4.3.3 Bad case: try accessing exchange rates with invalid base currency code.") @SpecAssertion(id = "433-A3", section = "4.3.3") public void testInvalidUsage_InvalidSourceCurrency() { for (String providerID : MonetaryConversions.getConversionProviderNames()) { if ("TestRateProvider".equals(providerID)) { continue; } ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID); try { prov.getExchangeRate("dhdjbdjd", "CHF"); Assert.fail( "ExchangeRateProvider should throw UnknownCurrencyException when an invalid source currency " + "is passed to getExchangeRate(String,String), provider: " + providerID); } catch (UnknownCurrencyException e) { // OK } } }
/** * comparator to sort the {@link MonetaryAmount} considering the * {@link ExchangeRate} * @param provider the rate provider to be used, not null. * @return the sort of {@link MonetaryAmount} using {@link ExchangeRate} */ public static Comparator<? super MonetaryAmount> sortValuable( ExchangeRateProvider provider) { return (m1, m2) -> { CurrencyConversion conversion = provider.getCurrencyConversion(m1 .getCurrency()); return m1.compareTo(conversion.apply(m2)); }; }
/** * Bad case: try accessing rates with inconsistent/invalid data.<p> * Hint: this assertion will require multiple tests to be written! */ @Test(description = "4.3.3 Bad case: try accessing exchange rates with invalid term currency code.") @SpecAssertion(id = "433-A3", section = "4.3.3") public void testInvalidUsage_InvalidTargetCurrency() { for (String providerID : MonetaryConversions.getConversionProviderNames()) { if ("TestRateProvider".equals(providerID)) { continue; } ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID); try { prov.getExchangeRate("CHF", "dhdjbdjd"); Assert.fail( "ExchangeRateProvider should throw UnknownCurrencyException when an invalid target currency " + "is passed to getExchangeRate(String,String), provider: " + providerID); } catch (UnknownCurrencyException e) { // OK } } }
/** * return the sum and convert all values to specific currency using the * provider, if necessary * @param provider the rate provider to be used, not null. * @param currency * currency * @return the list convert to specific currency unit */ public static BinaryOperator<MonetaryAmount> sum( ExchangeRateProvider provider, CurrencyUnit currency) { CurrencyConversion currencyConversion = provider .getCurrencyConversion(currency); return (m1, m2) -> currencyConversion.apply(m1).add( currencyConversion.apply(m2)); }
/** * Bad case: try accessing rates with inconsistent/invalid data.<p> * Hint: this assertion will require multiple tests to be written! */ @Test(description = "4.3.3 Bad case: try accessing exchange rates with null ConversionQuery.") @SpecAssertion(id = "433-A3", section = "4.3.3") public void testInvalidUsage_InvalidSourceCurrencyAndContext() { for (String providerID : MonetaryConversions.getConversionProviderNames()) { if ("TestRateProvider".equals(providerID)) { continue; } ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID); try { prov.getExchangeRate(null); Assert.fail("ExchangeRateProvider should throw NPE when an null ConversionQuery " + "is passed to getExchangeRate(ConversionQuery), provider: " + providerID); } catch (NullPointerException e) { // OK } } }