blob: 209159ca80618acdeadadbd4808eff52aef0498a [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*/
package org.eclipse.osbp.utils.currency;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Currency;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.joda.money.CurrencyUnit;
import org.joda.money.IllegalCurrencyException;
import org.joda.time.DateTime;
import org.eclipse.osbp.preferences.ProductConfiguration;
/**
* Euro based exchange reference rates
*/
public class EuroBasedExchangeReferenceRates {
// private static Boolean SYNCHRONIZOR = Boolean.FALSE;
private static final Object SYNCHRONIZOR = new Object();
/**
* @param currencyUnit the requested currency unit
* @return the reference rate for "today"
*/
public static BigDecimal getReferenceRate(CurrencyUnit currency) throws IllegalCurrencyException {
return getReferenceRate(currency, DateTime.now());
}
/**
* @param currencyUnit the requested currency unit
* @param referenceDate the reference date
* @return the reference rate
* @throws ParseException
* @throws IllegalCurrencyException
*/
public static BigDecimal getReferenceRate(CurrencyUnit currencyUnit, String referenceDate) throws IllegalCurrencyException, ParseException {
synchronized (SYNCHRONIZOR) {
return getReferenceRate(currencyUnit, Utilities.toIndexingDateTime(referenceDate));
}
}
/**
* @param currencyUnit the requested currency unit
* @param referenceDate the reference date
* @return the reference rate
*/
public static BigDecimal getReferenceRate(CurrencyUnit currency, DateTime referenceDate) throws IllegalCurrencyException {
synchronized (SYNCHRONIZOR) {
BigDecimal referenceRate;
if (CurrencyUnit.EUR.equals(currency)) {
referenceRate = BigDecimal.ONE;
}
else {
loadEuroForeignExchangeReferenceRates();
EuroBasedCurrencyConversionData data = sCurrencyConversions.get(currency);
if (data == null) {
throw new IllegalCurrencyException("No euro exchange for currency "+currency.getCurrencyCode()+" available");
}
referenceRate = data.getReferenceRate(referenceDate);
if (referenceRate == null) {
throw new IllegalCurrencyException("No euro exchange reference rate for currency "+currency.getCurrencyCode()+" for "+referenceDate+" available, only in ["+data.getOldestReferenceDate()+","+data.getNewestReferenceDate()+"]");
}
}
return referenceRate;
}
}
/**
* @return the alphanum sorted list of registered currencies
*/
public static List<CurrencyUnit> registeredCurrencies() {
loadEuroForeignExchangeReferenceRates();
ArrayList<CurrencyUnit> list = new ArrayList<CurrencyUnit>(sCurrencyConversions.keySet());
Collections.sort(list);
return list;
}
/**
* @param currencyUnit
* @return the Euro based currency conversion data for the currency unit given
*/
public static EuroBasedCurrencyConversionData getCurrencyConversionData(CurrencyUnit currencyUnit) {
loadEuroForeignExchangeReferenceRates();
return sCurrencyConversions.get(currencyUnit);
}
/**
* force reloading all Euro based currency conversions from a server
*/
public static void reloadEuroForeignExchangeReferenceRates() {
unloadEuroForeignExchangeReferenceRates();
loadEuroForeignExchangeReferenceRates();
}
/**
* force loading all Euro based currency conversions from a server if they are not loaded now
*/
public static void loadEuroForeignExchangeReferenceRates() {
synchronized (SYNCHRONIZOR) {
if (sCurrencyConversions == null) {
// --- prepare the internal cache ---
sCurrencyConversions = new HashMap<CurrencyUnit, EuroBasedCurrencyConversionData>();
// --- allways add Euro ---
sCurrencyConversions.put(CurrencyUnit.EUR, new EuroBasedCurrencyConversionData(CurrencyUnit.EUR));
// --- load previous and daily exchange rates from server ---
sLoadExceptions = new TreeMap<String,Exception>();
loadEuroForeignExchangeReferenceRates(ProductConfiguration.getEuroXRefRatesURLPrevious());
loadEuroForeignExchangeReferenceRates(ProductConfiguration.getEuroXRefRatesURLDaily());
// --- show any exceptions occurred while loading ---
for (String key : sLoadExceptions.keySet()) {
System.err.println(key);
}
}
}
}
/**
* free the internal cache
*/
public static void unloadEuroForeignExchangeReferenceRates() {
synchronized (SYNCHRONIZOR) {
sCurrencyConversions = null;
}
}
/**
* put the reference rate for the reference date for the currency unit into the internal cache
* @param referenceDate
* @param currencyUnit
* @param referenceRate
* @throws ParseException
*/
protected static void putReferenceRate(String referenceDate, CurrencyUnit currencyUnit, BigDecimal referenceRate) throws ParseException {
putReferenceRate(Utilities.toIndexingDateTime(referenceDate), currencyUnit, referenceRate);
}
/**
* put the reference rate for the reference date for the currency unit into the internal cache
* @param referenceDate
* @param currencyUnit
* @param referenceRate
*/
protected static void putReferenceRate(DateTime referenceDate, CurrencyUnit currencyUnit, BigDecimal referenceRate) {
EuroBasedCurrencyConversionData data = sCurrencyConversions.get(currencyUnit);
if (data == null) {
data = new EuroBasedCurrencyConversionData(currencyUnit);
sCurrencyConversions.put(currencyUnit, data);
}
data.putReferenceRate(referenceDate, referenceRate);
}
private static Map<CurrencyUnit, EuroBasedCurrencyConversionData> sCurrencyConversions;
private static Map<String,Exception> sLoadExceptions;
// @see http://www.vogella.com/tutorials/JavaXML/article.html
@SuppressWarnings("unchecked")
private static void loadEuroForeignExchangeReferenceRates(String fileurl) {
try {
// First, create a new XMLInputFactory
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
// Setup a new eventReader
URL url = new URL(fileurl);
InputStream in = url.openStream();
XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// read the XML document
String referenceDate = null;
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
// If we have an item element, we create a new item
if (startElement.getName().getLocalPart().equalsIgnoreCase("cube")) {
CurrencyUnit currencyUnit = null;
BigDecimal factor = null;
// We read the attributes from this tag
Iterator<Attribute> attributes = startElement.getAttributes();
while (attributes.hasNext()) {
Attribute attribute = attributes.next();
if (attribute.getName().toString().equalsIgnoreCase("time")) {
referenceDate = attribute.getValue();
}
else if (attribute.getName().toString().equalsIgnoreCase("currency")) {
try {
currencyUnit = CurrencyUnit.of(attribute.getValue());
}
catch (Exception e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
try {
Currency currency = Currency.getInstance(attribute.getValue());
if (currency != null) {
currencyUnit = CurrencyUnit.registerCurrency(currency.getCurrencyCode(), currency.getNumericCode(), currency.getDefaultFractionDigits(), new ArrayList<String>());
throw new IllegalArgumentException("Found currency '"+currency+"'");
}
}
catch (Exception e1) {
if ("ROL".equalsIgnoreCase(attribute.getValue())) {
// @see https://de.wikipedia.org/wiki/ISO_4217: ROL Leu 100 Bani Rumänien 1952–2005 Neuer Leu RON 10000:1
currencyUnit = CurrencyUnit.registerCurrency("ROL", 0, 2, new ArrayList<String>()); // Arrays.asList(new String[] {"RO"}));
Exception e2 = new IllegalArgumentException("Found currency 'ROL'");
sLoadExceptions.put(e2.getLocalizedMessage(),e2);
}
else {
sLoadExceptions.put(e1.getLocalizedMessage(),e1);
}
}
}
}
else if (attribute.getName().toString().equalsIgnoreCase("rate")) {
try {
factor = BigDecimal.valueOf(Double.parseDouble(attribute.getValue()));
}
catch (Exception e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
}
}
if ((currencyUnit != null) && (factor != null) && (referenceDate != null)) {
try {
putReferenceRate(referenceDate, currencyUnit, factor);
putReferenceRate(referenceDate, CurrencyUnit.EUR, BigDecimal.ONE);
}
catch (Exception e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
}
}
}
}
}
catch (FileNotFoundException e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
catch (XMLStreamException e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
catch (MalformedURLException e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
catch (IOException e) {
sLoadExceptions.put(e.getLocalizedMessage(),e);
}
}
}