| /** |
| * |
| * 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); |
| } |
| } |
| |
| } |