Implementing Bitcoin and java.util.Currency - java

I'm trying to add bitcoin as a currency to display on my site. I've got exchange rates and everything, but I keep getting an IllegalArgumentException whenever I use java.util.Currency.getInstance("BTC"). This makes sense since it's not included in the list of ISO 4217 currency codes, and also not in Java 7. I've seen a couple of options, but nothing that really solves my issue.
According to the Java platform docs, you can override a specific locale's currency by creating a file $JAVA_HOME/lib/currency.properties. This is a problem since bitcoin is not tied to a specific locale, nor should it be used in place of any country's currency.
Another similar situation was presented in this StackOverflow post, where China had a second currency code to be used, so the solution was to build your own currency.data file that added a second currency for the China locale. This is better, but there is still the issue of tying a currency to a locale.
Has anyone run into this problem or found a workaround? I know bitcoin is relatively new, but it'd be cool to be able to display prices in bitcoin format.

You cannot use BTC as the currency code for bitcoins under ISO 4217. BT is reserved for Bhutan. However, ISO 3166-1 reserves several country codes for user definition. Additionally, the wiki for ISO 4217 lists XBT as a currency code for bitcoins (unofficially, of course).
Locale.Builder b = new Locale.Builder();
b.setRegion("XB");
Locale xb = b.build();
Currency bitcoin = Currency.getInstance(xb);
Your currency.properties file will look like:
XB=XBT,000,3
Unfortunately, you cannot have 8 for the minor unit because the parsing for java.util.Currency only handles a minor unit of 0-3:
Pattern propertiesPattern = Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");

How to handle bitcoin money is explained well on the documentation. Take a look at this https://en.bitcoin.it/wiki/Proper_Money_Handling_(JSON-RPC)
Hope it helps

Related

Problems parsing iso8583 message

I've download code from here https://github.com/vikrantlabde/iso8583-Java and after some modifications I'm parsing almost fine my fields....
I defined the schema like this:
ISOSCHEMA.put("1","BITMAP");
ISOSCHEMA.put("2","NUM-2-19-0_0");
ISOSCHEMA.put("3","NUMERIC-0-6-0_0");
ISOSCHEMA.put("4","NUMERIC-0-12-0_0");
ISOSCHEMA.put("7","NUMERIC-0-10-0_0");
ISOSCHEMA.put("11","NUMERIC-0-6-0_0");
ISOSCHEMA.put("12","NUMERIC-0-6-0_0");
ISOSCHEMA.put("13","NUMERIC-0-4-0_0");
ISOSCHEMA.put("22","NUMERIC-0-3-0_0");
ISOSCHEMA.put("23","NUMERIC-0-3-0_0");
ISOSCHEMA.put("35","NUM-2-37-0_0");
ISOSCHEMA.put("41","FCHAR-0-8-0_0");
ISOSCHEMA.put("49","FCHAR-0-3-0_0");
ISOSCHEMA.put("55","NUM-3-999-0_0");
The problem is the field 55 that is a binary field. The standard documentation says it:
55 Reserved ISO B 255 LLLVAR (ISO DOCUMENTATION)
I'm having an error parsing a string that has the bitmap turned on for the field 55.
I'm having from the output:
820200409F36020004950500000000009A031409039C01005F2A0209789F02060000000005009F03060000000000009F10201F430200200000000000000000045895000000000000000000000000000000009F260840D26C4BA5577CFB9F2701809F370443DD7E879F1A0202509F3303E0B0C8
But I expect:
820200409F36020004950500000000009A031409039C01005F2A0201249F02060000000005009F03060000000000009F10201F430200200000000000000000045895000000000000000000000000000000009F260840D26C4BA5577CFB9F2701809F370443DD7E879F1A0202509F3303E0B0C8
The length of the iso payload converted is highly different too...
The program output is:
303130307238060020C280C28200313636353433323131313232333334343535303030303030303030303030303030303031313031363138333432363030323339343133333433303130313630373130303133373635343332313131323233333434353564333131303232303030393238333030313031303238343031373430393132343233303832303230303430394633363032303030343935303530303030303030303030394130333134303930333943303130303546324130323039373839463032303630303030303030303035303039463033303630303030303030303030303039463130323031463433303230303230303030303030303030303030303030303034353839353030303030303030303030303030303030303030303030303030303030303030394632363038343044323643344241353537374346423946323730313830394633373034343344443745383739463141303230323530394633333033453042304338
What I expect is:
30313030723806002080820031363635343332313131323233333434353530303030303030303030303030303030303131303136313833343236303032333934313333343330313031363037313030313337363534333231313132323333343435353D33313130323230303039323833303031303130323834303137343039313234313135820200409F36020004950500000000009A031409039C01005F2A0201249F02060000000005009F03060000000000009F10201F430200200000000000000000045895000000000000000000000000000000009F260840D26C4BA5577CFB9F2701809F370443DD7E879F1A0202509F3303E0B0C8
One advice is:
I have to make the explicit conversion to hex from the resultant byte[] and viceversa.
It is:
String isoMessage = ISOUtil.hexString(packIsoMsg("0100", isofields).getBytes());
And:
unpackIsoMsg(new String(ISOUtil.hex2byte(isoMessage), "UTF-8"));
What about the definition of this kind of fields in this class? I'm really a newbie with the standard but I arrived here because jpos doesn't work in an Android environment. Also I'm confused with the last mentioned conversion to hex.
Any help is really appreciated...
Kind regards.
DE55 is defined as a Tag-Lag-Value (TLV) field that is not in the normal Binary / text / or numeric packed format you see the rest of ISO-8583 messages typically but is in ASN.1 BER-TLV / X.690-0207 format.
Unless you account for the BER-TLV you will not successfully unpack DE55 unless it is for non-EMV/Tokenization purposes. It threw me at first as well as I was thinking something more straight forward. Be aware that sometimes the field transport format is actually longer in this format than the original plain text or other binary data output so it is not the most efficient.
There are a couple of other fields depending on the ISO specification may also use BER-TLV but DE55 is the industry standard field to use BER-TLV for EMV functionality replacing DE55's previous use as a generic and rarely used 'fee field'.
The ISO-7816 specification its ISO-8583 use in detail for EMV and Tokenization, as well there are other references and quick guides out there if you are just looking for something not so in-depth. All volumes of the ISO-7816 specification can be found openly on the internet for free, or can be purchased directly (spendy) from the ISO organization if you want them in the plain ISO format.
I am not familiar with the specific JAVA Git you referenced but this one has a help page on how to use BER-TLV. Oracle also has a page on dealing with BER-TLV here. BinaryFoo has a Git available as well.
For the purposes of initial testing, if your data is just test data (DO NOT USE PRODUCTION DATA!) you can use http://www.emvlab.org/tlvutils/ to verify your results. Which when I input your inputs it kicks out your expected output.
what is the field defined by sender in field 55.Assign the same in unpacking.If they are sending string it should be LLLVAR.
when sending ISO message header must be in hex format.hence they convert bytes to hex.
From the looks of it, you consider 5F2A020978 as wrong whereas you expect 5F2A020124. The EMV tag's 5F2A data (with length 02) is the transaction currency code. This means your transaction is performed in EURO currency instead of Canadian dollar as you expect. You can find a currency code list here.
Hope this helps.

How to handle Currency in Java 8?

What is the preferred way to handle currencies in Java 8?
The things that could be of interest would be
* Currency Full Name (e.g. United States Dollar)
* Currency Abbreviation (e.g. USD)
* Currency Symbol (e.g. $)
Any other thing that I might be missing here?
What are the best options?
Java 8 still uses java.util.Currency and ISO 4217 codes. From the Javadoc,
Represents a currency. Currencies are identified by their ISO 4217 currency codes. Visit the ISO web site for more information, including a table of currency codes.
The class is designed so that there's never more than one Currency instance for any given currency. Therefore, there's no public constructor. You obtain a Currency instance using the getInstance methods.
Users can supersede the Java runtime currency data by means of the system property java.util.currency.data.

Currency Symbol Internationalization Java

I'm trying to get the number format according to current locale but I have a problem with the currency symbol.
This is my method:
import java.util.Locale;
import java.text.NumberFormat;
public void i18nCurrency(Locale currentLocale) {
Double price = 9876543.21;
NumberFormat currencyFormatter =
NumberFormat.getCurrencyInstance(currentLocale);
System.out.println(currencyFormatter.format(price));
}
It prints: ¤ 9 876 543,21 for uk and ¤9.876.543,21 for german. The number format is correct, but I need to get the currency symbol as well. Why I can't get the symbol?
The symbol you're getting is a universal currency placeholder. It is displayed when currency is unknown.
You probably wonder why it is unknown. Well, from your description you simply called the method passing something like Locale.GERMAN. If you did, there is no way of knowing what currency to use, because:
Euro is a currency of Germany and Austria
Swiss Frank (SFr.) is a currency of Switzerland
Each of these countries has German as at least one of their official languages. In order to resolve the problem, you always need to pass a country, i.e. call the method with Locale.GERMANY as a parameter.
Now, the harder part. It is all fairly easy when you are working with desktop application. All you have to do is to detect current OS locale like this:
Locale currentLocale = Locale.getDefault(LocaleCategory.FORMAT);
However, this method won't work with web applications. I suspect this is the case. Well, the Locale that web browsers give you might be not suitable for formatting currencies, as they may lack information about the country.
The recommended way to solve this issue is to create user profile and ask users to select the Locale (separately for UI translations and formatting purposes).
I still have to point out one important thing, because I don't want you to run into problems. When you have some monetary value in your application (usually it should be an instance of BigDecimal class, as double is not suitable for this purpose), it represents some value in a specific currency. Be it Euro, British Pound, or a Dollar, but the value is specific. It doesn't really make sense to format this value for specific country currency, as you should first change the amount (I believe you understand why).
What you probably need instead, is overriding the currency symbol or currency code to match your currency. The format and the symbol placement should obviously stay intact.
Please consider this example:
Currency dollar = Currency.getInstance("USD");
NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.GERMANY); //this gets € as currency symbol
BigDecimal monetaryAmount = BigDecimal.valueOf(12.34d);
String originalEuros = fmt.format(monetaryAmount);
System.out.println(originalEuros);
fmt.setCurrency(dollar); // change the currency symbol to $
String modifiedDollars = fmt.format(monetaryAmount);
System.out.println(modifiedDollars);
This prints:
12,34 €
12,34 USD
Wait, why? The answer to your question lies in this subtle code snippet:
System.out.println(currency.getSymbol(Locale.GERMANY));
System.out.println(currency.getSymbol(Locale.US));
The result:
USD
$
What gets printed depends on a Locale. It is probably better this way, I cannot tell...
I believe, unless you are creating Internet currency exchange application, you should stick to my example.

How do I add the new currency code to Java?

The Chinese currency has the ISO 4217 code CNY. Since free global trading in that currency is restricted though, there's a second 'offshore' currency equivalent, called CNH. Wikipedia has a bit of summary of this all.
CNH isn't in ISO 4217, but I'd like to be able to use it in my app without having to write my own Currency class. Presumably there's some kind of list somewhere inside the JVM install. How do I go about adding additional currency codes?
EDIT: See this question for dealing with this in Java 7
Looks like support for this was added with Java 7.
For earlier versions, you could use an equivalent Currency class of your own devising, or less happily, replace the default java.util.Currency class (or java.util.CurrencyData, which contains the raw data) in your classpath (whitepaper).

What is the best way to display the currency symbol locale-dependent?

I would like to display the currency symbol ($, €) dependent on the current browser locale.
What is the best approach to do so?
I tried:
locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
System.out.println(locale); //gives: "en"
Currency.getInstance(locale).getSymbol(); //java.lang.IllegalArgumentException
Currency.getInstance(locale.GERMANY).getSymbol(); //gives €
How can I get the symbol based on locale dependent browser setting (which is "en" here)?
Update
locale.getLanguage() > "de"
locale.getDefault() > "de_DE"
Nevertheless, Currency.getInstance(locale).getSymbol(); fails.
Currency depends on the Country-Part of Locale. Since en does not contain a country part it is an illegal argument for creating a Currency instance.
In other words: Would you expect $, US$, AU$ or £ for Locale "en"? Or something else? There is no currency for "English". There are currencies for the US, GB, Australia and so on but not for English.
Edit
If the user configured his browser properly then you'll get indeed a Locale with both: Country and Language Part (e.g. en-US). These locales you can use the way you've done it in your question.
BUT you should consider using Geotargeting based on IP-Address. There exist databases like GEO-IP and MaxMind. Be aware that there are differences - an US student on semester abroad in Germany surfing with his laptop. His browser may return en-US but a GEO-IP database will target most probably to Germany. But maybe this is exactly what you want?!
Finally you can use one of these approaches as primary targeting factor and the second as backup. When both fail then switch to a default (e.g. US$)

Categories

Resources