![]() |
Download archive here |
![]() |
Version 1.1a, 27.11.2000
Status: complete
1. Introduction
1.1 The package magie.currency
1.2 Requirements
1.3 Usage
1.4 Structure
1.5 Application specific solutions
2.1 Currency
2.2 CurrencyUnit
2.3 Currency Conversion
2.4 Arithmetic Operations
2.5 Rounding Differences
2.6 Exceptions
3.1 Bean Properties
3.2 Model and Display Currency
3.3 Event Handling
4.1 Automated Tests
4.2 Test Application
5. Changes
6. References
The package magie.currency and all its sub-packages and extensions 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 2 of the License, or (at your option) any later version.
This library 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. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place,
Suite 330, Boston,
MA 02111-1307
USA
Or visit http://www.gnu.org/copyleft/lesser.html.
The legal requirements are defined in the EC Guideline No. 1103/97, Article 4, 5 (see [2]). The most important legal requirements include:
The package uses the following EUR-Currencies and exchange rates:
Unit | Country | Rate | Digits |
---|---|---|---|
ATS | Austria | 13.7603 | 2 |
BEF | Belgium | 40.3399 | 2 |
DEM | Germany | 1.95583 | 2 |
ESP | Spain | 166.386 | 2 |
FIM | Finland | 5.94573 | 2 |
FRF | France | 6.55957 | 2 |
IEP | Ireland | 0.787564 | 2 |
ITL | Italy | 1936.27 | 0 |
LUF | Luxembourg | 40.3399 | 2 |
NLG | Netherlands | 2.20371 | 2 |
PTE | Portugal | 200.482 | 2 |
EUR | European Union | 1.00000 | 2 |
The library, which consists of two core parts, can be used in the following way:
The following table provides an overview about the packages of the magie.currency library and its objectives:
package | description |
---|---|
magie.currency | The domain classes for the currency library: Currency, currency units and the required exceptions. |
magie.currency.ui | The classes of the CurrencyField bean, including events, bean property editors and bean icons |
magie.currency.testcase | A JUnit test class to test the domain classes |
magie.currency.ui.test | The Currency Test Application |
Non-EUR Currencies are not provided, nor mechanisms to perform currency conversion. In order to extend the package, the abstract Currency Unit classes may be subclassed to implement this behavior.
In addition, all application systems are responsible for
The core business functionality of the Euro converter is done within the classes of the currency domain package magie.currency. The following class diagram shows the classes of this package, the attributes and the business methods.
Figure 1: Class diagram domain classes
The class Currency, defined in the package magie.currency, is the model for monetary amounts used in the application's domain. It replaces objects of the type Double, which may be used in single currency unit application, in order to make monetary amounts dependent on their currency unit. Therefor the class Currency is composed of two attributes,
Field | Description |
---|---|
private double amount; | the monetary value of the currency |
private CurrencyUnit unit; | the unit of the currency |
In addition, the Currency class provides and encapsulates the business behavior for the domain related to monetary values, as there are:
Method | Functionality |
---|---|
Currency() | construction |
roundedToScale() | round to the defined scale |
add() | add a Currency to 'nother |
substract() | subtract a Currency from another |
multiply() | multiply Currency with a factor |
divide() | divide Currency by a factor or another Currency |
converted() | convert one currency to another unit; delegates to the currency unit of the Currency object to perform the conversion |
toString() | provide a formatted String representation |
displayString() | provide another formatted String representation (without Currency Unit) |
compareTo() | compare two Currencies |
Class CurrencyUnit is used as unit for Currency objects. There are two different Currency Unit implementation available within the magie.currency package:
The implementation of these classes encapsulates the EUR currencies and its rates and scales. This is done with the private method
/**
* create all required instances of the currency units
* and save them into the dictionary
*/
private static void initializeEurUnits() {
currencyUnits = new Hashtable();
currencyUnits.put("ATS", new EurCurrencyUnit("ATS", 13.7603d));
currencyUnits.put("BEF", new EurCurrencyUnit("BEF", 40.3399d));
currencyUnits.put("DEM", new EurCurrencyUnit("DEM", 1.95583d));
currencyUnits.put("ESP", new EurCurrencyUnit("ESP", 166.386d));
currencyUnits.put("FIM", new EurCurrencyUnit("FIM", 5.94573d));
currencyUnits.put("FRF", new EurCurrencyUnit("FRF", 6.55957d));
currencyUnits.put("IEP", new EurCurrencyUnit("IEP", 0.787564d));
currencyUnits.put("ITL", new EurCurrencyUnit("ITL", 1936.27d, 0));
currencyUnits.put("LUF", new EurCurrencyUnit("LUF", 40.3399d));
currencyUnits.put("NLG", new EurCurrencyUnit("NLG", 2.20371d));
currencyUnits.put("PTE", new EurCurrencyUnit("PTE", 200.482d));
currencyUnits.put("EUR", new EurCurrencyUnit("EUR", 1.00000d));
}
The core methods are listed in the following table:
Method | Functionality |
---|---|
CurrencyUnit() | construction |
getCurrencyUnit() | static method to retrieve an instance of CurrencyUnit for a given ID (String) |
registerCurrencyUnit() | static method to add additional instances to the list of available currency units Note, that you are not able to add additional EUR Currencies here! |
convert() | this method performs the Euro-conversion. It uses the following two (protected) methods to perform the conversion |
convertedToEUR() | convert a given Currency to EUR |
convertedFromEUR() | convert a given Currency from EUR |
The Euro-Conversion is performed in a two-step-procedure
The following method definition illustrates the implementation of this approach:
/** * convert Currency aCurrency into the given CurrencyUnit * * @param aCurrency (Currency) Currency to be converted * @param newCurrencyUnit (Type) destination CurrencyUnit * @return (Currency) the converted Currency */ public Currency convert(Currency aCurrency, CurrencyUnit newCurrencyUnit) throws CurrencyConversionException { Currency curr = aCurrency; // 1. convert currency to EUR if(!curr.getUnit().isEUR()) { curr = convertedToEUR(curr); } // 2. convert EUR to target currency if(!newCurrencyUnit.isEUR()) { curr = newCurrencyUnit.convertedFromEUR(curr); } return curr; }
I'd like to discuss some special behavior here:
The arithmetic operations of the Currency class are based on some general rules:
In the available library release the tracking of rounding differences resulting from arithmetic operations and/or conversions is not implemented. This fact is important especially for the addition of converted Currencies: Keep in mind, that the sum of converted currencies might be different from the converted sum of the currencies! The application using the library is responsible for the correct use of the classes by itself.
For passing error states to the applications, that uses the library, two Exception subclasses have been provided:
The CurrencyField is a subclass of JTextField which is aimed to edit Currency instances directly. Therefor the widget references a Currency object, to which it is connected. Applications can access this Currency object with the getCurrency() and setCurrency() methods of the field.
The CurrencyField is implemented as JavaBean, adding several properties to customise the field according to application requirements.
Property | Description |
---|---|
showUnit | Indicates if the currency unit is displayed |
resetInvalidEntry | If set to true, display is cleared after invalid entry |
displayCurrency | CurrencyUnit in which the currency is displayed |
modelCurrency | CurrencyUnit into which new currencies are converted |
In order to define the properties at built-time, for the properties showUnit and resetInvalidEntry are supported by two Property Editors, the classes ResetInvalidEntryEditor and ShowUnitEditor, which simply subclass PropertyEditorSupport.
Two CurrencyUnits can be passed to the CurrencyField to control its behavior with regards of conversion of currencies:
The Model Currency can thus be used to ensure, that inputs of monetary amounts are assigned with the right currency unit. For example, when the Model Currency of all Currency Fields is set to a system currency, all currencies in the system are processed in this currency unit. The Model Currency should be the "target" Currency Unit, e.g. the unit in which the data are stored in a database. The currency property f the Currency Field is converted to the Model Currency unit when the setModelCurrency() is called. After a focusLost() call of the Currency Field the input value is parsed, a Currency is instantiated and the result is converted to the Model Currency.
The Display Currency enables the end user of the library to display currencies in a preferred Currency Unit. For example, the user can select the Display Currency from a Choice within his application and all monetary amounts are displayed in this Currency Unit without impacting the Currency Unit, in which the data are stored or processed.
Both Currency Units may be set to null. The following table indicates, which behavior is gained with all possible use cases:
Model Currency | Display Currency | Display | Currency |
---|---|---|---|
null | null | Currency is displayed as is. | If no Currency Unit is entered, Currencies are parsed using the Currency Unit of the edited Currency |
a valid EurCurrencyUnit |
null | Currency is displayed in Model Currency | Currencies are created in the Model Currency. If a Currency Unit is entered the Currency is converted to the Model Currency. |
a valid EurCurrencyUnit |
the same EurCurrencyUnit |
Currency is displayed in Model/Display Currency | ditto. |
a valid EurCurrencyUnit |
another valid EurCurrencyUnit |
Currency is displayed in Display Currency | ditto. |
null | a valid EurCurrencyUnit |
Currency is displayed in the Display Currency | ditto. |
a CurrencyUnit | a valid EurCurrencyUnit |
Currency can not be displayed converted
Currency is displayed in Model Currency, red and always with unit |
Currencies are created in Model Currency. If a Currency Unit other than the Model Currency unit is entered, the input is not accepted. |
a valid EurCurrencyUnit |
a CurrencyUnit | Currency can not be displayed converted
Currency is displayed in Model Currency, red and always with unit |
ditto. |
The CurrencyField defines its own event to notify its CUrrencyChangeListeners about changes of the edited Currency. Therefore the following methods are used:
Method | Functionality |
---|---|
addCurrencyChangeListener | assign a CurrencyChangeListener to the field |
removeCurrencyChangeListener | removes a CurrencyChangeListener from the field |
fireCurrencyChange | notifies listeners about currency change |
For this event notification the interface CurrencyChangeListener, extending the EventListener interface, was introduced. It simply defines one method, the currencyChanged() method, which uses a CurrencyEvent, another extension of the class AWTEvent, as argument.
To test the Euro-Converter library a JUnit test case was implemented. The test case can be found in the package magie.currency.testcase in the class CurrencyTestCase. This class extends the class TestCase of the JUnit testing framework. For all tests a testing method is implemented as Java code. The table shows, what is being tested. See source code for further details!
Test method | Description |
---|---|
testCurrencyCreation | Tests the creation (construction and parsing) of Currencies |
testCalculation | Tests the arithmetic operations |
testConversion | Tests the currency conversion |
testRoundedToScale | Tests the rounding to the appropriate scale |
testLargeAmounts | Tests for correct processing or large amounts |
testNonEuroCurrencies | Tests for Exceptions converting none-EUR currencies |
testCurrencyCreationException | Tests for Exceptions occurring on bad Currency creation |
testCalculationException | Tests for Exceptions occurring on bad use of arithmetic operations |
To test the Currency Input Field bean and to demonstrate the usage of the classes the class CurrencyTestApplication in the package magie.currency.ui.test is used.
The core widget of the little test application is the CurrencyField, labelled "A Currency". This can be used to enter monetary amounts and display them. The display field labelled "The Model" provides a toString() representation of the Currency object edited by the CurrencyField. All bean properties as listed in the above can be changed by the Checkboxes and the Choices in the frame:
Figure 2: Currency Test Application
The frame itself is implemented as CurrencyChangeListener in order to be notified on Currency change. Here the currencyChanged() method displays the edited Currency in the display field.
The CurrencyField's handleException() method is overridden by an anonymous inner class, which simply outputs Exceptions, which are thrown by the Currency class to the CurrencyField (and usually caught and handled by the widget). With this mechanisms application specific behavior can be added to the bean, e.g. to notify the user about an invalid entry, using the application specific message handling mechanisms.
1.0 |
Creation |
|
1.0a |
Euro currency hierarchy introduced in order to provide flexibility to use non-Euro currencies |
|
1.0b |
Currency conversion is now delegated to the class EurCurrencyUnit |
|
1.1 |
urrency now works with BigDecimal amounts to increase precision |
|
1.1a |
Arithmethic methods changed to BigDecimal arithmetic; Package info updated |
[R1] GNU Lesser General Public License
[R2] Verordnung (EG) Nr. 1103/97 des Rates vom 17. Juni über bestimmte Vorschriften im Zusammenhang mit der Einführung des Euro
[R3] JUnit Documentation http://www.armaties.com/extreme.htm
[R4] Download Sources here.