Java tutorial
/******************************************************************************* * Copyright (c) 2016 Prowide Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Check the LGPL at <http://www.gnu.org/licenses/> for more details. *******************************************************************************/ package com.prowidesoftware.swift.model; import java.io.Serializable; import java.math.BigDecimal; import java.util.Currency; import java.util.logging.Logger; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import com.prowidesoftware.swift.model.field.AmountContainer; import com.prowidesoftware.swift.model.field.CurrencyContainer; import com.prowidesoftware.swift.model.field.Field; /** * A simple POJO to represent money, an amount associated with a currency. * <br /> * This might someday be replaced by an implementation of Java Money: https://java.net/projects/javamoney/pages/Home * * @author www.prowidesoftware.com * @since 7.8.8 */ final class CurrencyAmount implements Serializable { private static final long serialVersionUID = -7552352742105490377L; private static final transient Logger log = Logger.getLogger(CurrencyAmount.class.getName()); private final String currency; private final BigDecimal amount; /** * @param currency a not null currency * @param amount the value for the amount, may be <code>null</code> */ CurrencyAmount(final Currency currency, final BigDecimal amount) { this(currency.getCurrencyCode(), amount); } /** * @param currency a not null currency code * @param amount the value for the amount, may be <code>null</code> */ CurrencyAmount(final String currency, final BigDecimal amount) { super(); Validate.notNull(currency, "currency can not be null"); this.currency = currency; if (amount == null) { this.amount = BigDecimal.ZERO; } else { this.amount = amount; } } /** * @param currency a not null currency * @param value the value for the amount, may be <code>null</code> */ CurrencyAmount(final Currency currency, Number amount) { this(currency.getCurrencyCode(), amount); } /** * @param currency a not null currency code * @param value the value for the amount, may be <code>null</code> */ CurrencyAmount(final String currency, Number amount) { super(); this.currency = currency; if (amount == null) { this.amount = BigDecimal.ZERO; } else { if (amount instanceof BigDecimal) { this.amount = (BigDecimal) amount; } else if (amount instanceof Long) { this.amount = new BigDecimal(((Long) amount).longValue()); } else if (amount instanceof Integer) { this.amount = new BigDecimal(((Integer) amount).intValue()); } else if (amount instanceof Short) { this.amount = new BigDecimal(((Short) amount).intValue()); } else if (amount instanceof Double) { /* * we use valueOf instead of constructor because it uses a string under the covers to eliminate floating point rounding errors */ this.amount = BigDecimal.valueOf(((Double) amount).doubleValue()); } else { throw new IllegalArgumentException("class " + amount.getClass().getName() + " is not supported"); } } } public String getCurrency() { return currency; } public BigDecimal getAmount() { return amount; } /** * Creates a currency amount from an MT field.<br /> * The field must at least implement the {@linkplain AmountContainer} interface and * either have a currency component or implements the {@linkplain CurrencyContainer} * For some fields like the signed 19A or the 62[F,M] which have a debit/credit mark * component, the amount will be positive or negative accordingly. * * @param field a field with currency and amount components * @return the created currency amount object or null if field is null or invalid. */ /* * Do not use API from MTs and Field classes here to avoid cyclic dependency in code generation * Component numbers do not normally change, although keep code below in sync with fields 62FM, 19A and 33B. */ static CurrencyAmount of(Field field) { if (field != null && field instanceof AmountContainer) { /* * amount from interface */ BigDecimal amount = ((AmountContainer) field).amount(); if (amount == null) { log.warning( "cannot extract amount component from field " + field.getName() + ":" + field.getValue()); return null; } /* * special cases */ String currency = null; boolean negative = false; if ("62F".equals(field.getName()) || "62M".equals(field.getName())) { currency = field.getComponent(3); negative = StringUtils.equals("D", field.getComponent(1)); } else if ("19A".equals(field.getName())) { negative = StringUtils.equals("N", field.getComponent(2)); } else if ("33B".equals(field.getName())) { currency = field.getComponent(1); } /* * currency from interface */ if (currency == null && field instanceof CurrencyContainer) { currency = ((CurrencyContainer) field).currencyString(); } if (currency == null) { log.warning( "cannot extract currency component from field " + field.getName() + ":" + field.getValue()); return null; } if (negative) { amount = amount.negate(); } return new CurrencyAmount(currency, amount); } return null; } /** * Creates a currency amount from the first found field in the block * @param fields * @return */ static CurrencyAmount ofAny(SwiftTagListBlock block, String... fieldNames) { for (String fieldName : fieldNames) { Field field = block.getFieldByName(fieldName); if (field != null) { return of(field); } } return null; } /** * Creates a currency amount from the sum of all given fields. * Will return null if currencies not match. * @param fields fields to sum, currency must be the same for all * @return total or null if cannot create amount from any field or if not all fields currency match */ static CurrencyAmount ofSum(Field... fields) { if (fields == null || fields.length == 0) { return null; } BigDecimal total = null; String currency = null; for (Field field : fields) { CurrencyAmount ca = of(field); if (ca == null) { return null; } if (total == null) { total = ca.getAmount(); currency = ca.getCurrency(); } else if (StringUtils.equals(currency, ca.getCurrency())) { total = total.add(ca.getAmount()); } else { log.warning("cannot sum amounts with different currencies, expected " + currency + " and found " + ca.getCurrency() + " in field " + field.getName() + ":" + field.getValue()); return null; } } if (total != null && currency != null) { return new CurrencyAmount(currency, total); } else { return null; } } }