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

de.jfachwert.bank.Waehrung.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2024 by Oli B.
 *
 * 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 orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 29.07.24 by oboehm
 */
package de.jfachwert.bank

import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
import de.jfachwert.KFachwert
import de.jfachwert.KSimpleValidator
import de.jfachwert.money.pruefung.exception.LocalizedUnknownCurrencyException
import de.jfachwert.pruefung.NullValidator
import de.jfachwert.pruefung.exception.InvalidValueException
import java.util.*
import java.util.logging.Level
import java.util.logging.Logger
import javax.money.CurrencyContext
import javax.money.CurrencyUnit
import javax.money.UnknownCurrencyException

/**
 * Diese Klasse wurde ins money-Package kopiert. Sie ist nur noch aus
 * Kompatibiltaetsgruenden fuer eine Uebergangszeit im bank-Package.
 *
 * @deprecated: durch de.jfachwert.money.Waehrung ersetzt
 */
@JsonSerialize(using = ToStringSerializer::class)
open class Waehrung protected constructor(code: Currency, validator: KSimpleValidator) : KFachwert, Comparable, CurrencyUnit {

    companion object {

        private val log = Logger.getLogger(Waehrung::class.java.name)
        private val CACHE: MutableMap = WeakHashMap()
        private val VALIDATOR: KSimpleValidator = Validator()

        /** Default-Waehrung, die durch die Landeseinstellung (Locale) vorgegeben wird.  */
        @JvmField
        val DEFAULT_CURRENCY = defaultCurrency

        /** Default-Waehrung, die durch die Landeseinstellung (Locale) vorgegeben wird.  */
        @JvmField
        val DEFAULT = Waehrung(DEFAULT_CURRENCY)

        /** Die Euro-Waehrung als Konstante.  */
        @JvmField
        val EUR = of("EUR")

        /** Null-Konstante fuer Initialiserung.  */
        @JvmField
        val NULL = Waehrung("XXX")

        /**
         * Gibt die entsprechende Currency als Waehrung zurueck. Da die Anzahl der
         * Waehrungen ueberschaubar ist, werden sie in einem dauerhaften Cache
         * vorgehalten.
         *
         * @param currency Currency
         * @return Waehrung
         */
        @JvmStatic
        fun of(currency: Currency): Waehrung {
            val key = currency.currencyCode
            return CACHE.computeIfAbsent(key) { _: String? -> Waehrung(currency) }
        }

        /**
         * Gibt die entsprechende Currency als Waehrung zurueck.
         *
         * @param currencyUnit CurrencyUnit
         * @return Waehrung
         */
        @JvmStatic
        fun of(currencyUnit: CurrencyUnit): Waehrung {
            return if (currencyUnit is Waehrung) {
                currencyUnit
            } else {
                of(currencyUnit.currencyCode)
            }
        }

        /**
         * Gibt die entsprechende Currency als Waehrung zurueck.
         *
         * @param currency Waehrung, z.B. "EUR"
         * @return Waehrung
         */
        @JvmStatic
        fun of(currency: String): Waehrung {
            return of(toCurrency(currency))
        }

        /**
         * Ermittelt aus dem uebergebenen String die entsprechende
         * [Currency].
         *
         * @param name z.B. "EUR" oder auch ein einzelnes Symbol
         * @return die entsprechende Waehrung
         */
        @JvmStatic
        fun toCurrency(name: String): Currency {
            return try {
                Currency.getInstance(name)
            } catch (iae: IllegalArgumentException) {
                if (name.length <= 3) {
                    for (c in Currency.getAvailableCurrencies()) {
                        if (matchesCurrency(name, c)) {
                            return c
                        }
                    }
                    toFallbackCurrency(name, iae)
                } else {
                    try {
                        toCurrency(name.substring(0, 3))
                    } catch (ex: LocalizedUnknownCurrencyException) {
                        throw LocalizedUnknownCurrencyException(name, ex)
                    }
                }
            }
        }

        private fun matchesCurrency(name: String, c: Currency): Boolean {
            return name.equals(c.currencyCode, ignoreCase = true) || name.equals(c.symbol, ignoreCase = true)
        }

        private fun toFallbackCurrency(name: String, iae: IllegalArgumentException): Currency {
            return if (name == "\u20ac") {
                Currency.getInstance("EUR")
            } else {
                throw LocalizedUnknownCurrencyException(name, iae)
            }
        }

        /**
         * Validiert den uebergebenen Waehrungscode.
         *
         * @param code Waehrungscode als String
         * @return Waehrungscode zur Weiterverarbeitung
         */
        @JvmStatic
        fun validate(code: String): String {
            return VALIDATOR.validate(code)
        }

        /**
         * Lieft das Waehrungssymbol der uebergebenen Waehrungseinheit.
         *
         * @param cu Waehrungseinheit
         * @return z.B. das Euro-Zeichen
         */
        @JvmStatic
        fun getSymbol(cu: CurrencyUnit): String {
            return try {
                of(cu).symbol
            } catch (ex: IllegalArgumentException) {
                log.log(Level.FINE, "Kann das Symbol fuer '$cu' nicht ermitteln:", ex)
                cu.currencyCode
            }
        }

        /**
         * Ermittelt die Waehrung. Urspruenglich wurde die Default-Currency ueber
         * 
         * Currency.getInstance(Locale.getDefault())
         * 
* ermittelt. Dies fuehrte aber auf der Sun zu Problemen, da dort * die Currency fuer die Default-Locale folgende Exception hervorrief: *
         * java.lang.IllegalArgumentException
         * at java.util.Currency.getInstance(Currency.java:384)
         * at de.jfachwert.money.Geldbetrag.<clinit>
         * ...
         * 
* * @return normalerweise die deutsche Currency */ private val defaultCurrency: Currency get() { val locales = arrayOf(Locale.getDefault(), Locale.GERMANY, Locale.GERMAN) for (loc in locales) { try { return Currency.getInstance(loc) } catch (iae: IllegalArgumentException) { log.log(Level.FINE,"Keine Waehrung fuer Locale '$loc' verhanden - versuche es mit einer anderen.") log.log(Level.FINER,"Details:", iae) } } return Currency.getAvailableCurrencies().iterator().next() } init { CACHE[DEFAULT_CURRENCY.currencyCode] = DEFAULT } } /** * Liefert die Waehrung als Currency zurueck. * * @return Waehrung als Currency */ val code: Currency /** * Darueber kann eine Waehrung angelegt werden. * * @param code z.B. "EUR" */ constructor(code: String) : this(toCurrency(code)) /** * Darueber kann eine Waehrung angelegt werden. * * @param code Waehrung */ constructor(code: Currency) : this(code, NullValidator()) /** * Liefert die Currency zurueck. * * @return die Currency aus java.util. */ val currency: Currency get() = code /** * Liefert den Waehrungscode. * * @return z.B. "EUR" */ override fun getCurrencyCode(): String { return code.currencyCode } /** * Liefert den numerischen Waehrungscode. * * @return z.B. 978 fuer EUro */ override fun getNumericCode(): Int { return code.numericCode } /** * Liefert die Anzahl der Nachkommastellen einer Waehrung. * * @return meist 2, manchmal 0 */ override fun getDefaultFractionDigits(): Int { return code.defaultFractionDigits } override fun getContext(): CurrencyContext { throw UnsupportedOperationException("not yet implemented") } /** * Liefert das Waehrungssymbol. * * @return z.B. "$" */ val symbol: String get() = code.symbol /** * Zum Vergleich wird der Waehrungscode herangezogen und alphabetisch * verglichen. * * @param other die andere Waerhung * @return eine negative Zahl wenn die ander Waehrung alphabetisch * danach kommt. */ override fun compareTo(other: CurrencyUnit): Int { return currencyCode.compareTo(other.currencyCode) } /** * Zwei Waehrungen sind nur dann gleich, wenn sie vom gleichen Typ sind . * * @param other zu vergleichender Waehrung * @return true bei Gleichheit * @see java.lang.Object.equals */ override fun equals(other: Any?): Boolean { if (other !is Waehrung) { return false } return code == other.code } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ override fun hashCode(): Int { return code.hashCode() } /** * Als toString-Implementierung wird der Waehrungscode ausgegeben. * * @return z.B. "EUR" */ override fun toString(): String { return currencyCode } init { this.code = validator.verify(code) } /** * Dieser Validator ist fuer die Ueberpruefung von Waehrungen vorgesehen. * * @since 3.0 */ class Validator : KSimpleValidator { /** * Wenn der uebergebene Waehrungsstring gueltig ist, wird er * unveraendert zurueckgegeben, damit er anschliessend von der * aufrufenden Methode weiterverarbeitet werden kann. Ist der Wert * nicht gueltig, wird eine [ValidationException] geworfen. * * @param value Waehrungs-String, der validiert wird * @return Wert selber, wenn er gueltig ist */ override fun validate(value: String): String { try { toCurrency(value) } catch (ex: IllegalArgumentException) { throw InvalidValueException(value, "currency") } catch (ex: UnknownCurrencyException) { throw InvalidValueException(value, "currency") } return value } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy