All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javamoney.moneta.spi.AbstractCurrencyConversion Maven / Gradle / Ivy

Go to download

JSR 354 provides an API for representing, transporting, and performing comprehensive calculations with Money and Currency. This module implements JSR 354.

There is a newer version: 1.4.1
Show newest version
/*
 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.javamoney.moneta.spi;

import javax.money.CurrencyUnit;
import javax.money.MonetaryAmount;
import javax.money.MonetaryOperator;
import javax.money.NumberValue;
import javax.money.convert.ConversionContext;
import javax.money.convert.CurrencyConversion;
import javax.money.convert.CurrencyConversionException;
import javax.money.convert.ExchangeRate;

import org.javamoney.moneta.function.MonetaryOperators;

import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Objects;

/**
 * Abstract base class used for implementing currency conversion.
 *
 * @author Anatole Tresch
 * @author Werner Keil
 */
public abstract class AbstractCurrencyConversion implements CurrencyConversion {

    private final CurrencyUnit termCurrency;
    private final ConversionContext conversionContext;

    public static final String KEY_SCALE = "exchangeRateScale";

    public AbstractCurrencyConversion(CurrencyUnit termCurrency, ConversionContext conversionContext) {
        Objects.requireNonNull(termCurrency);
        Objects.requireNonNull(conversionContext);
        this.termCurrency = termCurrency;
        this.conversionContext = conversionContext;
    }

    /**
     * Access the terminating {@link CurrencyUnit} of this conversion instance.
     *
     * @return the terminating {@link CurrencyUnit} , never {@code null}.
     */
    @Override
    public CurrencyUnit getCurrency() {
        return termCurrency;
    }

    /**
     * Access the target {@link ConversionContext} of this conversion instance.
     *
     * @return the target {@link ConversionContext}.
     */
    @Override
    public ConversionContext getContext() {
        return conversionContext;
    }

    /**
     * Get the exchange rate type that this {@link MonetaryOperator} instance is
     * using for conversion.
     *
     * @return the {@link ExchangeRate} to be used, or null, if this conversion
     * is not supported (will lead to a
     * {@link CurrencyConversionException}.
     * @see #apply(MonetaryAmount)
     */
    @Override
    public abstract ExchangeRate getExchangeRate(MonetaryAmount amount);

    /*
     * (non-Javadoc)
     * @see javax.money.convert.CurrencyConversion#with(javax.money.convert.ConversionContext)
     */
    public abstract CurrencyConversion with(ConversionContext conversionContext);

    /**
     * Method that converts the source {@link MonetaryAmount} to an
     * {@link MonetaryAmount} based on the {@link ExchangeRate} of this
     * conversion.
     *
     * @param amount The source amount
     * @return The converted amount, never null.
     * @throws CurrencyConversionException if conversion failed, or the required data is not available.
     * @see #getExchangeRate(MonetaryAmount)
     */
    @Override
    public MonetaryAmount apply(MonetaryAmount amount) {
        if (termCurrency.equals(Objects.requireNonNull(amount).getCurrency())) {
            return amount;
        }
        ExchangeRate rate = getExchangeRate(amount);
        if (rate==null || !amount.getCurrency().equals(rate.getBaseCurrency())) {
            throw new CurrencyConversionException(amount.getCurrency(),
                    this.termCurrency, this.conversionContext);
        }

        NumberValue factor = rate.getFactor();
        factor = roundFactor(amount, factor);

        Integer scale = rate.getContext().get(KEY_SCALE, Integer.class);
        if(scale==null || scale < 0) {
        	return amount.multiply(factor).getFactory().setCurrency(rate.getCurrency()).create();
        } else {
        	return amount.multiply(factor).getFactory().setCurrency(rate.getCurrency()).create().with(MonetaryOperators.rounding(scale));
        }
    }

    /**
     * Optionally rounds the factor to be used. By default this method will only round
     * as much as it is needed, so the factor can be handled by the target amount instance based on its
     * numeric capabilities. Rounding is applied only if {@code amount.getContext().getMaxScale() > 0} as follows:
     * 
    *
  • If the amount provides a {@link MathContext} as context property this is used.
  • *
  • If the amount provides a {@link RoundingMode}, this is used (default is * {@code RoundingMode.HALF_EVEN}).
  • *
  • By default the scale used is scale of the conversion factor. If the acmount allows a higher * scale based on {@code amount.getContext().getMaxScale()}, this higher scale is used.
  • *
* * @param amount the amount, not null. * @param factor the factor * @return the new NumberValue, never null. */ protected NumberValue roundFactor(MonetaryAmount amount, NumberValue factor) { if (amount.getContext().getMaxScale() > 0) { MathContext mathContext = amount.getContext().get(MathContext.class); if(mathContext==null){ int scale = factor.getScale(); if (factor.getScale() > amount.getContext().getMaxScale()) { scale = amount.getContext().getMaxScale(); } RoundingMode roundingMode = amount.getContext().get(RoundingMode.class); if(roundingMode==null){ roundingMode = RoundingMode.HALF_EVEN; } mathContext = new MathContext(scale, roundingMode); } return factor.round(mathContext); } return factor; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + " [MonetaryAmount -> MonetaryAmount" + ']'; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy