Friday, 18 May 2012

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library

Again let me dive straight in to catch this culprit. So! how did it happen? You have a method call which uses or wants to use JNA to perform some native system calls. You then fired your call only to be greeted with:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'c': 
The specified module could not be found.

 at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:145)
 at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:188)
 at com.sun.jna.Library$Handler.<init>(Library.java:123)
 at com.sun.jna.Native.loadLibrary(Native.java:255)
 at com.sun.jna.Native.loadLibrary(Native.java:241)
WTH is this you asked yourself?! well I have to be honest, this is just the beginning. Let me demostrate this with a simple JNA call to illustrate where this exception came from. Let us assume below is your native functions you want to invoke. Again I will make an assumption that, your native code was compiled on windows enviroment using perhaps Cygwin gcc command.
//File Name: native.c

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#ifdef _WIN32
#   include <io.h>

typedef signed int md_t;

int fchmod(const char * path, md_t mode)
{
 return (_chmod(path, (mode==777 ? _S_IWRITE : _S_IREAD )));
}

#else
int fchmod(const char * path, md_t mode)
{
 return(chmod(path, mode));
}

#endif
int main(int argv, char ** argvs)
{
  return 0;
}
Here again let us assume this is your Java application from which you want to call the native functions:
import com.sun.jna.Library;
import com.sun.jna.Native;

public class demoJNA
{
  public interface Natives extends Library
  {
    public int fchmod(String path, int mode);
  }

  public static void main(String[] args)
  {
    Natives posix = (Natives) Native.loadLibrary("c", Natives.class);
    posix.fchmod("c:\\somefile.txt", 777);
  }
}
Out of patience you compiled your java application, executed it and hence the exception. Ok stop here! lets revisit your application, first notice the call;
Native.loadLibrary("c", Natives.class); 
is "c" the library output name given when you compiled your native code? Let say I compile the native code above like this;
gcc -o native.dll native.c
the call then should look like this;
Natives posix = (Natives) Native.loadLibrary("native", Natives.class);
One more thing, Is the ouput library file located at your classpath? if not then please do move it there, because it from there JNA will be looking when the call Native.loadLibrary is fired.

Monday, 14 May 2012

Controlling method recursion to avoid StackOverflowError - Java RMI call as Example

There are times that you want the flexibility of your method to be able to recurse itself when an exception occurs to re-attempt without recursing too deeply. This could possibly be a call to remote Socket or RMI which has been restarted, and therefore the stub or the connector object instance needs re-allocating or other. I have opted to use an RMI call as an example due to reasons which will be clear pretty shortly. Say you are allocating and using RMI connection stub via singleton instance as shown bellow;
public class Foo
{
 private RemoteStub stub;
 public RemoteStub getRemoteConnection()
 {
  if(stub==null)
  {
    try
    {
     this.stub= ((RemoteStub) Naming.lookup(...));
    }
    catch (Exception e)
    {
      e.printStackTrace(System.out);
    }
  }
  return stub;
 }
}
Chances are when the remote server instance is restarted, your stub object will not re-allocate itself to hold the new instance. And hence an attempt to make remote calls will yeild the exception below;
java.rmi.ConnectException: Connection refused to host: 192.168.0.1; nested exception is: 
    java.net.ConnectException: Connection timed out: connect
A quick and easy way to fix this issue is to have your connection stub builder method ignore null check or simply no singleton instance for your remote calls, which means every remote call will have the connection stub re-allocated and returned. As said, this is quick and easy, but doesn't come cheap neither. And so, this is the reason why I have decided to use this example as an insight into controlling method recursion, to make it pretty easy to follow through.

An alternative and yet effective approach is to extend your connection stub builder method to re-allocate on demand. This way when above exception occurs you can recurse your method to re-attempt once and ignore. The assumption here is that if you do re-attempt and fails again, there is a high chance remote server is down or something is preventing you from connecting. Now, let us go ahead and expand on getRemoteConnection() method and introduce the techiques for re-attempting the call.
public class Foo
{
 private RemoteStub stub;
 private AtomicBoolean reconnect;
 
 public Foo()
 {
  reconnect= new AtomicBoolean(false);
 }

 public RemoteStub getRemoteConnection()
 {
  //Extended the builder to handle on demand
  if(stub==null || reconnect.get())
  {
    try
    {
     this.stub= ((RemoteStub) Naming.lookup(...));
     reconnect.set(false);
    }
    catch (Exception e)
    {
      e.printStackTrace(System.out);
    }
  }
  return stub;
 }

 protected void reconnect()
 {
  reconnect.set(true);
 }
}
As you can see above, we have expanded on the remote stub builder method to handle on demand call to re-allocate the remote stub object. This gives us the flexibility in our calling method to fire reconnect() whenever we re-attempt. One issue we have not raised so far is the fact that, there is a high chance re-attempt via recursion will fail subsequently due to assumption made above. Here we are likely to enter into deep recursion and hence StackOverflowError.
  public class FooCaller extends Foo
  {
    private static final CharSequence failedConnect = "Connection refused";
    public void callRemoteMethod()
    {
      try
      {
        int status = getRemoteConnection().doSomething();
        System.out.println("Remote call - " + (status > -1 ? "Succeeded" : "Failed"));
      }
      catch (RemoteException e)
      {
        if (e.getMessage().contains(failedConnect))
        {
         // re-attempt
         reconnect();
         callRemoteMethod();
        }
      }
    }
  }
To control this we will use a token object and a simple stack handler, which does ensure recursions are detached straight after first re-attempt call, to avoid StackOverflowError. See below for extended version of FooCaller class with method handler for issuing attempt token and generic handler method for handling re-attempt calls to avoid code verbosity.
/**
 Re-Attempt Token
*/
public class ReAttemptToken
{
  public long lastAttempted = System.currentTimeMillis();
  public String method;

  public ReAttemptToken(String method)
  {
    this.method = method;
  }
}
.. simple stack object to control the life span of ReAttemptToken held for a specific method recurse;
/**
 * Simple stack object for holding recursive method recall to avoid {@link StackOverflowError}.
 * 
 * @author Bright Dadson
 * 
 */
@SuppressWarnings("serial")
public class ReAttemptStack extends ArrayList<ReAttemptToken>
{
  /**
   * Creates an empty Stack.
   */
  public ReAttemptStack()
  {
  }

  /**
   * Pushes an item onto the top of this stack. This has exactly the same effect as: 
* *
   * add(item)
   * 
* *
* * @param item the item to be pushed onto this stack. * @return the item argument. * @see java.util.ArrayList#add */ public ReAttemptToken push(ReAttemptToken item) { add(item); return item; } /** * Tests if this stack is empty. * * @return true if and only if this stack contains no items; false otherwise. */ public boolean empty() { return size() == 0; } /** * Locate and return items in this stack. * * @param o the desired {@link ReAttemptToken}. * @return found object else null */ public synchronized ReAttemptToken locate(ReAttemptToken o) { int i = this.searchToken(o.method); return (i >= 0) ? get(i) : null; } /** * Scan this stack to search for token with method same as passed argument * * @param method - token method * @return index of the token within this stack */ public int searchToken(String method) { for (int i = 0; i < size(); i++) { if (get(i).method.equals(method)) return i; } return -1; } }
.. and finally a new extended version of FooCaller with stack control handlers;
 public class FooCaller extends Foo
 {
    private long reAttemptTTL = 3 * 1000;
    private ReAttemptStack stack;
    private static final CharSequence failedConnect = "Connection refused";

    private FooCaller()
    {
      stack = new ReAttemptStack();
    }

    /**
     * Typical remote call
     * 
     */
    public void callRemoteMethod()
    {
      try
      {
        int status = getRemoteConnection().doSomething();
        System.out.println("Remote call - " + (status > -1 ? "Succeeded" : "Failed"));
      }
      catch (RemoteException e)
      {
        if (e.getMessage().contains(failedConnect))
        {
          try
          {
            ReAttemptToken token = getReAttemptToken("callRemoteMethod");
            reAttemptRemoteCall(this.getClass().getMethod("callRemoteMethod"), new Object[] {}, token);
          }
          catch (Exception ex)
          {}
        }else e.printStackTrace();
      }
    }

    /**
     * This method issues token to calling functions. If the token is not expired and hence still exist, the method returns the same token from the
     * stack for usage.
     * 
     * @param method
     * @return
     */
    private ReAttemptToken getReAttemptToken(String method)
    {
      int tokenIndex;
      if ((tokenIndex = stack.searchToken(method)) > -1)
      {
        return stack.get(tokenIndex);
      }
      return (new ReAttemptToken(method));
    }

    /**
     * Using the method we can retry remote reconnection, obtain a fresh connection stub and re-invoke the failed method. In the aid of re-attempt
     * token passing control, we can avoid indefinite recurssion from occuring when we re-invoke. Each token is expired every 3secs to enable recall.
     * @param methodToRecurse
     * @param params
     * @param token
     */
    private void reAttemptRemoteCall(Method methodToRecurse, Object[] params, ReAttemptToken token)
    {
      try
      {
        long now = System.currentTimeMillis();
        boolean attempt = false;
        if (stack.locate(token) == null)
        {
          stack.push(token);
          attempt = true;
        }
        else if ((stack.locate(token) != null) && now > (reAttemptTTL + token.lastAttempted))
        {
          stack.remove(token);
          stack.push(getReAttemptToken(token.method));
          attempt = true;
        }
        if (attempt)
        {
          System.err.println("Re-Attempting failed remote call **");
          reconnect();
          methodToRecurse.invoke(this, params);
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
    }
  }
Disclaimer
The code and technique adopted in this post has only been written to demonstrate how to control StackOverFlowError from occuring in method calls which require recursion, to re-attempt situations where an exceptions is possible to occur due to anticipated reasons. Also note that, the approach adopted here is not required for all situations.

Drop a comment if you've spotted a bug, known enhancement possible to extend the technique or any relevant comment which is helpful to other readers.

Friday, 11 May 2012

Waiting on a Thread without blocking Java Swing EDT

Event dispatching threads are used as background thread to avoid blocking queues, or simply to avoid components from freezing while performing multi-tasking. JTabbedPane is a brilliant component to demostrate typical blocking EDT issues. Assume you have JTable on two panels placed on JTabbedPane, the first panel make adaptor call to remote server to pull collection of rows to render in the table and the second does pretty much the same thing.

Without EDT, there is a great posibility that while the first panel is building its table model with data fetched from remote server, the second tab will be blocked(freeze) to prevent access. One typical solution to this culprit is to use EventQueue.invokeLater(Runnable) method. But for a long running method, this option is not viable as it is only appropriate for simple application threads that needs to update the GUI.

A more viable approach to enable you wait on a Thread while performing a long running routine is using the worker design pattern. SwingWorker enables you perform a long running task without blocking EDT. To demostrate this, let assume this business scenario, we have a system which performs several concurrent executions. We want a button ActionEvent to call a delegated shutdown method, which will await on all the threads to complete before asking the JVM to bring the system to halt.

This request can be achieved in several ways, but because we do not want our waiting thread to block Swing EDT, we will first place the delegate call to shutdown in EventQueue.invokeLater(Runnable) and then use worker pattern to handle the long waiting thread as shown below.

» Assume this is our JButton action listner event
    closeButton.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        EventQueue.invokeLater(new Runnable()
        {
          public void run()
          {
            shutDown();
          }
        });
      }
    });
» Assume this is our delegated shutdown method
 public void shutDown()
 {
    try
     {
      closeButton.setEnabled(false);//disable the button to avoid futher clicks
      ShutdownWorker task = new ShutdownWorker();
      task.execute();
    }
    catch (Exception e)
    {
      // just force it
      System.exit(0);
    }
  }
» SwingWorker handler class
  class ShutdownWorker extends SwingWorker<Void, Void>
  {
    public Void doInBackground() throws Exception
    {
       System.out.println("halting system");
       performSomeLongAwaitCall();

      return null;
    }

    public void done()
    {
      // shutdown
      System.gc();
      System.exit(0);
    }
    
    private void performSomeLongAwaitCall()
    {
      try
      {
       while(some condition is not true)
       {
         //TODO: perform the thread shutdown or 
         //await on all the threads to shutdown gracefully
         [...]
         Thread.sleep(2000);
       }
      }
      catch (InterruptedException ignore)
      {}
    }
  }
Adopting this approach for tasks that takes longer to complete is much effective for Swing UI applications. As you have seen above, we used a class which extends SwingWorker, implemented its abstract method doInBackground to handle the long awaiting call to shutting down the application to avoid blocking other events dispatched from userbility.

The approach gives the user the flexibility to perform several tasks and also add power to your application. Because this post is targeted to non-blocking Swing EDT, I will not dive more deeper into SwingWorker itself here. But surely there is more to it than just using it for controlling blocking threads. I will leave the rest to you to explore - but do hope this post has help you in some way to adapt an approach for handling Swing Event dispatching design pattern.

Disclaimer
The code above has only been written to demonstrate how to avoid waiting threads blocking Swing EDT, but not a complete working program.

Wednesday, 4 April 2012

Convert currency using Google API calculator and Java

So why do I propose this option against the numerous converter apis out there on the web? For me the answer is pretty simple, I can't think of any API out there which stands virtually at par with google on various matching grounds. Free, Robust, 247uptime for critical systems and over all easy to use. Google currency calculator like most of its apis like Dojo, Ext Core, jQuery etc. are used both by google developement team and developers all over. These apis are accessible so long as the google project is alive.

Although I will not stick my neck on it and say it is "mission-critical", which I believe it is, I can only say - if you dont trust the google conversion api on the grounds of critical usage, then you're going to find it difficult to arrive on a specific api for your currency conversion, unless you are looking to subscribe for one which the providers can stick their neck on and say it is "mission-critical". To demonstrate how easy and quick it is, I opted to use Core Java to create a simple currency converter util to interract with the api.


A request to convert say 12GBP to USD, simply translates to:
http://www.google.com/ig/calculator?h1=en&q=12gbp=?usd
With a typical standard Jason result as shown below:
{lhs: "12 British pounds",rhs: "19.0188 U.S. dollars",error: "",icc: true}

This makes it pretty straight forward, all we need now is an enumumeration class to hold all the various currency codes, and helper functions relevant for a specific convertion. Took time to compile this to support various currencies your application is possible to support.
/**Currency and code used mostly for conversion and other purposes
 * 
 * @author Bright Dadson
 *
 */
public enum Currency
{
  UAE_Dirham("AED", "UAE Dirham"),
  Afghanistan_Afghani("AFA", "Afghanistan Afghani"),
  Albanian_Lek("ALL", "Albanian Lek"),
  Neth_Antilles_Guilder("ANG", "Neth Antilles Guilder"),
  Argentine_Peso("ARS", "Argentine Peso"),
  Australian_Dollar("AUD", "Australian Dollar"),
  Aruba_Florin("AWG", "Aruba Florin"),
  Barbados_Dollar("BBD", "Barbados Dollar"),
  Bangladesh_Taka("BDT", "Bangladesh Taka"),
  Bahraini_Dinar("BHD", "Bahraini Dinar"),
  Burundi_Franc("BIF", "Burundi Franc"),
  Bermuda_Dollar("BMD", "Bermuda Dollar"),
  Brunei_Dollar("BND", "Brunei Dollar"),
  Bolivian_Boliviano("BOB", "Bolivian Boliviano"),
  Brazilian_Real("BRL", "Brazilian Real"),
  Bahamian_Dollar("BSD", "Bahamian Dollar"),
  Bhutan_Ngultrum("BTN", "Bhutan Ngultrum"),
  Botswana_Pula("BWP", "Botswana Pula"),
  Belize_Dollar("BZD", "Belize Dollar"),
  Canadian_Dollar("CAD", "Canadian Dollar"),
  Swiss_Franc("CHF", "Swiss Franc"),
  Chilean_Peso("CLP", "Chilean Peso"),
  Chinese_Yuan("CNY", "Chinese Yuan"),
  Colombian_Peso("COP", "Colombian Peso"),
  Costa_Rica_Colon("CRC", "Costa Rica Colon"),
  Cuban_Peso("CUP", "Cuban Peso"),
  Cape_Verde_Escudo("CVE", "Cape Verde Escudo"),
  Cyprus_Pound("CYP", "Cyprus Pound"),
  Czech_Koruna("CZK", "Czech Koruna"),
  Dijibouti_Franc("DJF", "Dijibouti Franc"),
  Danish_Krone("DKK", "Danish Krone"),
  Dominican_Peso("DOP", "Dominican Peso"),
  Algerian_Dinar("DZD", "Algerian Dinar"),
  Estonian_Kroon("EEK", "Estonian Kroon"),
  Egyptian_Pound("EGP", "Egyptian Pound"),
  Ethiopian_Birr("ETB", "Ethiopian Birr"),
  Euro("EUR", "Euro"),
  Falkland_Islands_Pound("FKP", "Falkland Islands Pound"),
  British_Pound("GBP", "British Pound"),
  Ghanian_Cedi("GHC", "Ghanian Cedi"),
  Gibraltar_Pound("GIP", "Gibraltar Pound"),
  Gambian_Dalasi("GMD", "Gambian Dalasi"),
  Guinea_Franc("GNF", "Guinea Franc"),
  Guatemala_Quetzal("GTQ", "Guatemala Quetzal"),
  Guyana_Dollar("GYD", "Guyana Dollar"),
  Hong_Kong_Dollar("HKD", "Hong Kong Dollar"),
  Honduras_Lempira("HNL", "Honduras Lempira"),
  Croatian_Kuna("HRK", "Croatian Kuna"),
  Haiti_Gourde("HTG", "Haiti Gourde"),
  Hungarian_Forint("HUF", "Hungarian Forint"),
  Indonesian_Rupiah("IDR", "Indonesian Rupiah"),
  Israeli_Shekel("ILS", "Israeli Shekel"),
  Indian_Rupee("INR", "Indian Rupee"),
  Iraqi_Dinar("IQD", "Iraqi Dinar"),
  Iceland_Krona("ISK", "Iceland Krona"),
  Jamaican_Dollar("JMD", "Jamaican Dollar"),
  Jordanian_Dinar("JOD", "Jordanian Dinar"),
  Japanese_Yen("JPY", "Japanese Yen"),
  Kenyan_Shilling("KES", "Kenyan Shilling"),
  Cambodia_Riel("KHR", "Cambodia Riel"),
  Comoros_Franc("KMF", "Comoros Franc"),
  North_Korean_Won("KPW", "North Korean Won"),
  Korean_Won("KRW", "Korean Won"),
  Kuwaiti_Dinar("KWD", "Kuwaiti Dinar"),
  Cayman_Islands_Dollar("KYD", "Cayman Islands Dollar"),
  Kazakhstan_Tenge("KZT", "Kazakhstan Tenge"),
  Lao_Kip("LAK", "Lao Kip"),
  Lebanese_Pound("LBP", "Lebanese Pound"),
  Sri_Lanka_Rupee("LKR", "Sri Lanka Rupee"),
  Liberian_Dollar("LRD", "Liberian Dollar"),
  Lesotho_Loti("LSL", "Lesotho Loti"),
  Lithuanian_Lita("LTL", "Lithuanian Lita"),
  Latvian_Lat("LVL", "Latvian Lat"),
  Libyan_Dinar("LYD", "Libyan Dinar"),
  Moroccan_Dirham("MAD", "Moroccan Dirham"),
  Moldovan_Leu("MDL", "Moldovan Leu"),
  Malagasy_Franc("MGF", "Malagasy Franc"),
  Macedonian_Denar("MKD", "Macedonian Denar"),
  Myanmar_Kyat("MMK", "Myanmar Kyat"),
  Mongolian_Tugrik("MNT", "Mongolian Tugrik"),
  Macau_Pataca("MOP", "Macau Pataca"),
  Mauritania_Ougulya("MRO", "Mauritania Ougulya"),
  Maltese_Lira("MTL", "Maltese Lira"),
  Mauritius_Rupee("MUR", "Mauritius Rupee"),
  Maldives_Rufiyaa("MVR", "Maldives Rufiyaa"),
  Malawi_Kwacha("MWK", "Malawi Kwacha"),
  Mexican_Peso("MXN", "Mexican Peso"),
  Malaysian_Ringgit("MYR", "Malaysian Ringgit"),
  Mozambique_Metical("MZM", "Mozambique Metical"),
  Namibian_Dollar("NAD", "Namibian Dollar"),
  Nigerian_Naira("NGN", "Nigerian Naira"),
  Nicaragua_Cordoba("NIO", "Nicaragua Cordoba"),
  Norwegian_Krone("NOK", "Norwegian Krone"),
  Nepalese_Rupee("NPR", "Nepalese Rupee"),
  New_Zealand_Dollar("NZD", "New Zealand Dollar"),
  Omani_Rial("OMR", "Omani Rial"),
  Panama_Balboa("PAB", "Panama Balboa"),
  Peruvian_Nuevo_Sol("PEN", "Peruvian Nuevo Sol"),
  Papua_New_Guinea_Kina("PGK", "Papua New Guinea Kina"),
  Philippine_Peso("PHP", "Philippine Peso"),
  Pakistani_Rupee("PKR", "Pakistani Rupee"),
  Polish_Zloty("PLN", "Polish Zloty"),
  Paraguayan_Guarani("PYG", "Paraguayan Guarani"),
  Qatar_Rial("QAR", "Qatar Rial"),
  Romanian_Leu("ROL", "Romanian Leu"),
  Russian_Rouble("RUB", "Russian Rouble"),
  Saudi_Arabian_Riyal("SAR", "Saudi Arabian Riyal"),
  Solomon_Islands_Dollar("SBD", "Solomon Islands Dollar"),
  Seychelles_Rupee("SCR", "Seychelles Rupee"),
  Sudanese_Dinar("SDD", "Sudanese Dinar"),
  Swedish_Krona("SEK", "Swedish Krona"),
  Singapore_Dollar("SGD", "Singapore Dollar"),
  St_Helena_Pound("SHP", "St Helena Pound"),
  Slovenian_Tolar("SIT", "Slovenian Tolar"),
  Slovak_Koruna("SKK", "Slovak Koruna"),
  Sierra_Leone_Leone("SLL", "Sierra Leone Leone"),
  Somali_Shilling("SOS", "Somali Shilling"),
  Surinam_Guilder("SRG", "Surinam Guilder"),
  Sao_Tome_Dobra("STD", "Sao Tome Dobra"),
  El_Salvador_Colon("SVC", "El Salvador Colon"),
  Syrian_Pound("SYP", "Syrian Pound"),
  Swaziland_Lilageni("SZL", "Swaziland Lilageni"),
  Thai_Baht("THB", "Thai Baht"),
  Tunisian_Dinar("TND", "Tunisian Dinar"),
  Tonga_Pa_anga("TOP", "Tonga Pa'anga"),
  Turkish_Lira("TRL", "Turkish Lira"),
  Turkey_Lira("TRY", "Turkey Lira"),
  Trinidad_And_Tobago_Dollar("TTD", "Trinidad And Tobago Dollar"),
  Taiwan_Dollar("TWD", "Taiwan Dollar"),
  Tanzanian_Shilling("TZS", "Tanzanian Shilling"),
  Ukraine_Hryvnia("UAH", "Ukraine Hryvnia"),
  Ugandan_Shilling("UGX", "Ugandan Shilling"),
  US_Dollar("USD", "US Dollar"),
  Uruguayan_New_Peso("UYU", "Uruguayan New Peso"),
  Venezuelan_Bolivar("VEB", "Venezuelan Bolivar"),
  Vietnam_Dong("VND", "Vietnam Dong"),
  Vanuatu_Vatu("VUV", "Vanuatu Vatu"),
  Samoa_Tala("WST", "Samoa Tala"),
  CFA_Franc_BEAC("XAF", "CFA Franc (BEAC)"),
  Silver_Ounces("XAG", "Silver Ounces"),
  Gold_Ounces("XAU", "Gold Ounces"),
  East_Caribbean_Dollar("XCD", "East Caribbean Dollar"),
  CFA_Franc_BCEAO("XOF", "CFA Franc (BCEAO)"),
  Palladium_Ounces("XPD", "Palladium Ounces"),
  Pacific_Franc("XPF", "Pacific Franc"),
  Platinum_Ounces("XPT", "Platinum Ounces"),
  Yemen_Riyal("YER", "Yemen Riyal"),
  Yugoslav_Dinar("YUM", "Yugoslav Dinar"),
  South_African_Rand("ZAR", "South African Rand"),
  Zambian_Kwacha("ZMK", "Zambian Kwacha"),
  Zimbabwe_Dollar("ZWD", "Zimbabwe Dollar");

  private final String currencyCode;
  private final String currencyFullName;
  private static final Mapa<String, String> currencyLookup = new HashMap<String, String>();

  static
  {
    for (Currency currencyEnum : EnumSet.allOf(Currency.class))
    {
      currencyLookup.put(currencyEnum.getCurrencyCode(), currencyEnum.getCurrencyCodeFullName());
    }
  }
  
  private Currency(String currencyCode, String currencyFullName)
  {
    this.currencyCode = currencyCode;
    this.currencyFullName = currencyFullName;
  }

  public String getCurrencyCode()
  {
    return this.currencyCode;
  }

  public String getCurrencyCodeFullName()
  {
    return currencyFullName;
  }
  
  /**Using the currency code as an argument, fetch and return associated full name
   * 
   * @param currencyCode - The Currency Code of which you want to retrieve its full reference name.
   */
  public static String getCurrencyCodeFullName(String currencyCode)
  {
    if(currencyLookup.containsKey(currencyCode))
    {
      return currencyLookup.get(currencyCode);
    }
    return null;
  }

  /***Checks and return currency code*/
  public static String getCurrency(String currencyCode)
  {
    if(currencyLookup.containsKey(currencyCode))
    {
      return currencyCode;
    }
    return null;
  }

}
We have all the required currency codes available, what we now need is the converter handler which will accept currency code for both the currency to convert from and the final currency to convert to.

Calling getConvertedValue(..) passing in the amount, currency code to convert to and from, will build and submit a query against google api, retrieve the result and extract the converted value.

We could have happily done this with Jason dependency to our project to perform the extraction. Yet if you're like me who prefer to keep things lightweight and free from overlayered dependencies, then core classic java URL and string manipulations will surely do the simple tasks.
/**
 * Using this class, we convert currencies to its foreign exchange. This class uses google calculator to perform the conversion process
 * @author Bright Dadson
 */
public final class Converter
{
  private static final String error = "error:";
  private static final String noErrorFound = "\"\"";
  private static final String regExp = "-?\\d+(.\\d+)?";

  private int valueToConvert;
  private String convertFrom, convertTo;

  public Converter()
  {}

  /**
   * Convert submitted value from and to the submitted conversion codes.
   * 
   * @param valueToConvert - Amount to convert
   * @param convertFrom - Currency code to convert from
   * @param convertTo - Currency code to convert to
   * @return
   */
  public double getConvertedValue(int valueToConvert, String convertFrom, String convertTo)
  {
    try
    {
      this.valueToConvert = valueToConvert;
      this.convertFrom = convertFrom;
      this.convertTo = convertTo;
      String convertedValue = extractConvertedValue(convert());
      if (convertedValue != null && isNumeric(convertedValue))
      {
        BigDecimal roundVal = new BigDecimal(convertedValue);
        roundVal.round(new MathContext(2, RoundingMode.HALF_UP));
        return roundVal.doubleValue();
      }
    }
    catch (Exception ex)
    {
      ex.printStackTrace(System.out);
    }
    return 0d;
  }

  /**Connect to Google api using http GET request to perform the currency conversion**/
  private String convert()
  {
    try
    {
      String code = String.valueOf("/ig/calculator?h1=en&q=" + valueToConvert + "" + convertFrom + "=?" + convertTo);
      URL converterUrl = new URL("http://www.google.com" + code);
      URLConnection urlConnection = converterUrl.openConnection();

      InputStream inputStream = urlConnection.getInputStream();
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

      String conversionResult = bufferedReader.readLine();
      bufferedReader.close();
      inputStream.close();
      urlConnection = null;

      return conversionResult;
    }
    catch (Exception e)
    {
      e.printStackTrace(System.out);
    }
    return null;
  }

  /**If error is found within the response string, throw runtime exception to report, else parse the result for extraction**/
  private String extractConvertedValue(String convertedResult) throws Exception
  {
    String[] convertedResStrings = convertedResult.split(",");
    for (int i = 0; i < convertedResStrings.length; i++)
    {
      if ((convertedResStrings[i].contains(error)) && convertedResStrings[i].split(" ")[1].equals(noErrorFound))
      {
        String convertedValue = extract(convertedResStrings[i - 1]);
        if (!(convertedValue.isEmpty()))
        {
          return convertedValue;
        }
      }
      else if ((convertedResStrings[i].contains(error)) && !convertedResStrings[i].split(" ")[1].equals(noErrorFound))
      {
        throw new RuntimeException("Error occured while converting amount: "+convertedResStrings[i].split(" ")[1]);
      }
    }
    return null;
  }

  private String extract(String str)
  {
    StringBuffer sBuffer = new StringBuffer();
    Pattern p = Pattern.compile(regExp);
    Matcher m = p.matcher(str);
    if (m.find())
    {
      sBuffer.append(m.group());
    }
    return sBuffer.toString();
  }

  private boolean isNumeric(String str)
  {
    return str.matches(regExp);
  }

}


Example usage
  public static void main(String[] args)
  {
   Converter converter = new Converter();
   //Convert 12GBP to USD and print the result to console
   System.out.println(converter.getConvertedValue(12, Currency.British_Pound.getCurrencyCode(),
                       Currency.US_Dollar.getCurrencyCode()));
  }
As you can see, it is pretty straight forward and free from injected dependencies. If you have read from the top to the bottom of this post - chances are you have already fired your IDE and started playing with this. Do let me know of any enchancement, suggestions or if this directed you on the right selective path.