ExchangeRateCache.java

package com.tradecloud.domain.costing.clean;

import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.costing.CostGroup;
import com.tradecloud.domain.costing.CostLinePayerType;
import com.tradecloud.domain.exchangerate.DefaultRateOfExchanges;
import com.tradecloud.domain.exchangerate.RateOfExchanges;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author jon
 */
public class ExchangeRateCache {

    final Map<RateCacheKey, BigDecimal> spotRateCache = new HashMap<>();

    final Map<RateCacheKey, BigDecimal> forwardRateCache = new HashMap<>();
    //e.g USD to EUR
    final Map<RateCacheKey, BigDecimal> foreignCurrencyToForeignCache = new HashMap<>();

    final Map<RateCacheKey, DefaultRateOfExchanges> spotAndFwdRateCache = new HashMap<>();

    private Date cacheTimeFtoF;

    private static final long EXPIRY_TIME = 300000;

    public boolean hasCachedSpotRate(Currency currency, CostLinePayerType costLinePayerType) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType);
        return spotRateCache.containsKey(key);
    }

    public BigDecimal getCachedSpotRate(Currency currency, CostLinePayerType costLinePayerType) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType);
        return spotRateCache.get(key);
    }

    public void putCachedSpotRate(Currency currency, CostLinePayerType costLinePayerType, BigDecimal value) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType);
        spotRateCache.put(key, value);
    }

    public boolean hasCachedForwardRate(Currency currency, Date date, CostLinePayerType costLinePayerType) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType, date);
        return forwardRateCache.containsKey(key);
    }

    public BigDecimal getCachedForwardRate(Currency currency, Date date, CostLinePayerType costLinePayerType) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType, date);
        return forwardRateCache.get(key);
    }

    public void putCachedForwardRate(Currency currency, Date date, CostLinePayerType costLinePayerType, BigDecimal value) {
        RateCacheKey key = new RateCacheKey(currency, costLinePayerType, date);
        forwardRateCache.put(key, value);
    }

    public void putForeignCurrencyToForeignCache(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType,
                                                 BigDecimal value) {
        RateCacheKey key = new RateCacheKey(transactionCurrency, costingCurrency, costLinePayerType);
        foreignCurrencyToForeignCache.put(key, value);
        this.cacheTimeFtoF = new Date();
    }

    public void putSpotAndFwdRateCache(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType,
                                       Date date, Long orderId, CostGroup costGroup, DefaultRateOfExchanges value) {
        RateCacheKey key = new RateCacheKey(transactionCurrency, costingCurrency, costLinePayerType, date, orderId, costGroup);
        spotAndFwdRateCache.put(key, value);
        this.cacheTimeFtoF = new Date();
    }

    public DefaultRateOfExchanges getSpotAndFwdRateCache(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType,
                                                         Date date, Long orderId, CostGroup costGroup) {
        RateCacheKey key = new RateCacheKey(transactionCurrency, costingCurrency, costLinePayerType, date, orderId, costGroup);
        return spotAndFwdRateCache.get(key);
    }

    public BigDecimal getCachedForeignToForeign(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType) {
        RateCacheKey key = new RateCacheKey(transactionCurrency, costingCurrency, costLinePayerType);
        return foreignCurrencyToForeignCache.get(key);
    }

    public void clearForwardRateCache() {
        forwardRateCache.clear();
    }

    public void clearSpotRateCache() {
        spotRateCache.clear();
    }

    public void clearForeignCurrencyToForeignCache() {
        foreignCurrencyToForeignCache.clear();
    }

    public RateOfExchanges getCachedRateOfExchanges(Currency currency, Date date, CostLinePayerType costLinePayerType) {
        return new DefaultRateOfExchanges(getCachedSpotRate(currency, costLinePayerType), getCachedForwardRate(currency, date, costLinePayerType));
    }

    public void setCacheTimeFtoF(Date cacheTimeFtoF) {
        this.cacheTimeFtoF = cacheTimeFtoF;
    }

    public void clearTimeBasedCache() {
        if (cacheTimeFtoF != null) {
            long daysBetween2 = DateUtils.getMilliSecondsBetween2(cacheTimeFtoF, new Date());
            if (daysBetween2 > EXPIRY_TIME) {
                foreignCurrencyToForeignCache.clear();
            }
        } else {
            foreignCurrencyToForeignCache.clear();
        }

    }

    private class RateCacheKey {
        Currency transactionCurrency;
        Currency costingCurrency;
        CostLinePayerType costLinePayerType;
        Date date;
        private Long orderid; //required when dealing with rates from treasury
        private CostGroup costGroup;

        public RateCacheKey(Currency transactionCurrency, CostLinePayerType costLinePayerType, Date date) {
            this.transactionCurrency = transactionCurrency;
            this.costLinePayerType = costLinePayerType;
            this.date = date;
        }

        public RateCacheKey(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType) {
            this.transactionCurrency = transactionCurrency;
            this.costingCurrency = costingCurrency;
            this.costLinePayerType = costLinePayerType;
        }

        public RateCacheKey(Currency transactionCurrency, Currency costingCurrency, CostLinePayerType costLinePayerType,
                            Date date, Long orderId, CostGroup costGroup) {
            this.transactionCurrency = transactionCurrency;
            this.costingCurrency = costingCurrency;
            this.costLinePayerType = costLinePayerType;
            this.date = date;
            this.costGroup = costGroup;
            this.orderid = orderId;
        }

        public RateCacheKey(Currency transactionCurrency, CostLinePayerType costLinePayerType) {
            this.transactionCurrency = transactionCurrency;
            this.costLinePayerType = costLinePayerType;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            RateCacheKey key = (RateCacheKey) o;
            return new EqualsBuilder().append(transactionCurrency, key.transactionCurrency).append(costingCurrency, key.costingCurrency).
                    append(costLinePayerType, key.costLinePayerType).append(date, key.date)
                    .append(costGroup, key.costGroup).append(orderid, key.orderid).isEquals();

        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder().append(transactionCurrency).append(costingCurrency).append(costLinePayerType)
                    .append(date).append(costGroup).append(orderid).toHashCode();

        }
    }
}