Tuesday, August 28, 2012

JSON GSON

JSON is a wide spread data description format used to exchange JavaScript Objects.
It is pretty widely used for web API.
Today, I will focus on the exploitation of this kind of data in Java, with the pretty well done GSon library.
First, call the API (a simple GET with the arguments in the URL) that provide the data, this is done simply by this code :

public static String call(String url) throws IOException {
    BufferedReader bis = null;
    InputStream is = null;
    try {
        URLConnection connection = new URL(url).openConnection();
        is = connection.getInputStream();
        // warning of UTF-8 data
        bis = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        String line = null;
        StringBuffer result = new StringBuffer();
        while ((line = bis.readLine()) != null) {
            result.append(line);
        }
        return result.toString();
    } finally {
        if (bis != null) {
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Note : we use a InputStreamReader(is, "UTF-8") in order to manage correctly UTF-8 data that we'll retrieve in some Japanese, French or other exotic languages.

Ok, the String result will be the something, for example like that :

{
     "first-name": "John",
     "last-name": "Smith",
     "age": 25,
     "address":
     {
         "street-address": "21 2nd Street",
         "city": "New York",
         "state": "NY",
         "postal-code": "10021"
     },
     "phone-number":
     [
         {
           "type": "home",
           "number": "212 555-1234"
         },
         {
           "type": "fax",
           "number": "646 555-4567"
         }
     ]
 }

To process this String, we'll use the magic GSon.

The GSon library will try to parse the JSon formatted string and map the data to a given Java Person Object. GSon used reflection to do such a trick, so the attributes types and names of the target java Object will need to be matchable with the JSon string structure.
In the previous example, the Person object will need to have a structure that match the JSon object, that is to say, will have 5 attributes named "first-name", "last-name", "age", "address", and "phone-number".

First of all, what we see here, is that an attribute cannot be called first-name in Java, because the '-' character is not permitted in java attribute names. No problem, we'll declare a firstName attribute, and specify that it's JSon serialized name id "first-name" by using a @SerializedName annotation.

We'll obtain an attribute declared like this :

@SerializedName("first-name") private String firstName;

Of course same trick is applied for the "last-name" attribute.
The age is simply declared as a int, here we keep the same attribute name in JavaScript and in Java :

private int age;

Ok, now the address, which is a complex Object (we can see it with the {...} that represents a structure.
So we'll map it with a Java Object Address, which following the same principle as above, which give us :

private class Address {

    @SerializedName("street-address") private String streetAddress;

    private String city;

    private String state;

    @SerializedName("postal-code") private int postalCode;

}

Remain the phone numbers, here the [...] characters point out that we are dealing with a collections of objects.
We'll then map it with a java.util.List of PhoneNumber Objects as below :

@SerializedName("phone-number") private List<PhoneNumber> phoneNumber;

Where a PhoneNumber is the given object :

private class PhoneNumber {

    private String type;
    private String number;
}

OK, so now our Object Person is completed and looks like that :

private class Person {

    @SerializedName("first-name") private String firstName;

    @SerializedName("last-name") private String lastName;

    private int age;

    private Address address;

    @SerializedName("phone-number") private List<PhoneNumber> phoneNumber;

}

We are done. A call to Gson will instantiate a Person Java Object and populate it with the flux.

Person data = new Gson().fromJson(json, Person .class); 

 That give us :



Tuesday, August 14, 2012

Programmatically restart a Java application

Today I'll talk about a famous problem : restarting a Java application. It is especially useful when changing the language of a GUI application, so that we need to restart it to reload the internationalized messages in the new language. Some look and feel also require to relaunch the application to be properly applied.

A quick Google search give plenty answers using a simple :

Runtime.getRuntime().exec("java -jar myApp.jar");
System.exit(0);

This indeed basically works, but this answer that does not convince me for several reasons :
1) What about VM and program arguments ? (this one is secondary in fact, because can be solve it quite easily).
2) What if the main is not a jar (which is usually the case when launching from an IDE) ?
3) Most of all, what about the cleaning of the closing application ? For example if the application save some properties when closing, commit some stuffs etc.
4) We need to change the command line in the code source every time we change a parameter, the name of the jar, etc.

Overall, something that works fine for some test, sandbox use, but not a generic and elegant way in my humble opinion.

Ok, so my purpose here is to implement a method :

public static void restartApplication(Runnable runBeforeRestart) throws IOException {

...

}

that could be wrapped in some jar library, and could be called, without any code modification, by any Java program, and by solving the 4 points raised previously.

Let's start by looking at each point and find a way to answer them in an elegant way (let's say the most elegant way that I found).

1) How to get the program and VM arguments ? Pretty simple, by calling a :

ManagementFactory.getRuntimeMXBean().getInputArguments();

Concerning the program arguments, the Java property sun.java.command we'll give us both the main class (or jar) and the program arguments, and both will be useful.

String[] mainCommand = System.getProperty("sun.java.command").split(" ");

2) First retrieve the java bin executable given by the java.home property :

String java = System.getProperty("java.home") + "/bin/java";

The simple case is when the application is launched from a jar. The jar name is given by a mainCommand[0], and it is in the current path, so we just have to append the application parameters mainCommand[1..n] with a -jar to get the command to execute :

String cmd = java + vmArgsOneLine + "-jar " + new File(mainCommand[0]).getPath() + mainCommand[1..n];

We'll suppose here that the Manifest of the jar is well done, and we don't need to specify either the main nor the classpath.

Second case : when the application is launched from a class. In this case, we'll specify the class path and the main class :

String cmd = java + vmArgsOneLine + "-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0] + mainCommand[1..n];


3) Third point, cleaning the old application before launching the new one.
To do such a trick, we'll just execute the Runtime.getRuntime().exec(cmd) in a shutdown hook.
This way, we'll be sure that everything will be properly clean up before creating the new application instance.

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
        ...
    }
});

Run the runBeforeRestart that contains some custom code that we want to be executed before restarting the application :

if(beforeRestart != null) {
    beforeRestart.run();
}

And finally, call the
System.exit(0);

And we're done. Here is our generic method :

/**
 * Restart the current Java application
 * @param runBeforeRestart some custom code to be run before restarting
 * @throws IOException
 */
public static void restartApplication(Runnable runBeforeRestart) throws IOException {
    try {
        // java binary
        String java = System.getProperty("java.home") + "/bin/java";
        // vm arguments
        List<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
        StringBuffer vmArgsOneLine = new StringBuffer();
        for (String arg : vmArguments) {
            // if it's the agent argument : we ignore it otherwise the
            // address of the old application and the new one will be in conflict
            if (!arg.contains("-agentlib")) {
                vmArgsOneLine.append(arg);
                vmArgsOneLine.append(" ");
            }
        }
        // init the command to execute, add the vm args
        final StringBuffer cmd = new StringBuffer("\"" + java + "\" " + vmArgsOneLine);
        // program main and program arguments (be careful a sun property. might not be supported by all JVM) 
        String[] mainCommand = System.getProperty("sun.java.command").split(" ");
        // program main is a jar
        if (mainCommand[0].endsWith(".jar")) {
            // if it's a jar, add -jar mainJar
            cmd.append("-jar " + new File(mainCommand[0]).getPath());
        } else {
            // else it's a .class, add the classpath and mainClass
            cmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]);
        }
        // finally add program arguments
        for (int i = 1; i < mainCommand.length; i++) {
            cmd.append(" ");
            cmd.append(mainCommand[i]);
        }
        // execute the command in a shutdown hook, to be sure that all the
        // resources have been disposed before restarting the application
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    Runtime.getRuntime().exec(cmd.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        // execute some custom code before restarting
        if (beforeRestart != null) {
            beforeRestart.run();
        }
        // exit
        System.exit(0);
    } catch (Exception e) {
        // something went wrong
        throw new IOException("Error while trying to restart the application", e);
    }
}

Sunday, August 12, 2012

UnsatisfiedLinkError in a JavaWebStart application

Yes ! Me too ! I have spent a tremendous amount of time dealing with trouble using JNI in a Java Web Start or an Applet environment. And by searching on my friend Google, I have found out that I'm not the only Java developer on the Java world to have dealt with this kind of trouble ...
Sometimes, it works pretty fine, especially if you use Java Web Start to wrap your application (Swing/ Eclipse RCP or Applet), you just have to follow a quite simple procedure that can be automated with a simple Ant script (for more details about Java Web Start, check the Lopica web site that is pretty well done) :

1) Jar the native lib :
 <jar destfile="lib/nativewin.jar" basedir="native/win/" includes="some.dll"/>  

2) Sign the Jars your application :
 <target name="genkey">  
   <delete file="${keystore}"/>  
   <genkey alias="alias" keystore="${keystore}" storepass="storepass" validity="900">  
     <dname>  
       <param name="CN" value="CN"/>  
       <param name="OU" value="OU"/>  
       <param name="O" value="O"/>  
       <param name="C" value="C"/>  
     </dname>  
   </genkey>  
 </target>  
 <target name="signjar" depends="genkey">  
   <signjar alias="alias" keystore="${keystore}" storepass="storepass">  
     <fileset dir="${dest.dir}/">  
       <include name="**/*.jar" />  
     </fileset>  
   </signjar>  
 </target> 

3) Add the good tag in your JNLP :
 <resources os="Windows" arch="x86">  
      <nativelib href="lib/nativewin.jar"/>  
 </resource> 
And everything is fine. Yes sometimes everything is OK, but sometimes, for some dark reasons that I don't really understand, with some native libs and not with others, especially when you don't have time to spend on this kind of problem, and always on the production environment, because when testing on your development environment, you have forgotten to delete the native lib of your PATH ... So sometimes, the application crashes with a famous :

java.lang.UnsatisfiedLinkError: no foobar in java.library.path

Here we are. You check your JNLP : seems good. You check the jar that contains the native lib : hmm OK. It's 10pm and you're still at office, "It must be some little silly thing that I'm forgetting. Tomorrow, I'll recheck that I'll probably found the solution in 10 minutes".
Naive of you ...

The following day, you spend an entire morning checking all these little things, reboot 5 times your computer, but it's still here : the UnsatisfiedLinkErrorOfTheDeath ...

The first workaround is of course to copy the native libs in a folder that you will previously had in your PATH. The copy can be done by some installer code of the program, for example by a code that will look like this one (the native is located in the Jar, so we need to access it as a Stream) :

InputStream src = SomeClass.class.getResourceAsStream("/pathToTheLib/" + libName);

File libDestFile = new File(installLibFilePath);

FileOutputStream out = null;

try {
       out = new FileOutputStream(libDestFile);
       byte[] buffer = new byte[256];
       int read = 0;
       while ((read = src.read(buffer)) > 0) {
              out.write(buffer, 0, read);
              read = src.read(buffer);
       }
} catch (FileNotFoundException e) {
       e.printStackTrace();
} catch (IOException e) {
       e.printStackTrace();
} finally {
       // close
       try {
              if (out != null) {
                     out.close();
              }
       } catch (IOException e) {
              e.printStackTrace();
       }
}

Here we have two possibilities : either our program is loading the native lib, in this case, we replace the instruction :
java.lang.System.load(libDestFile.getAbsolutePath());
By a :
java.lang.System.load(libName);
But if it is a library (another Jar) that is loading the native lib, we are stuck. In this case, we have to set some PATH env property manually so that the ClassLoader find the native lib, and your Java developer soul cry hard when thinking of doing such a disgraceful thing.
Ok, so how do we do such a trick in Java ... Well, as it is said i the exception message, we need to add the library to the java.library.path property.
What is this property ? It is used when the java.lang.ClassLoader will load the first native library to initialize its field usr_paths which is a String array. Indeed, in the loadLibrary method, we can see this code :
if (sys_paths == null) {
       usr_paths = initializePath("java.library.path");
       sys_paths = initializePath("sun.boot.library.path");
}
So seeing this code, we understand that it is useless to override this property, by adding the folder where we will copy our library, after the JVM as been launch, because we'll be too late, the sys_paths field will be initialized, so the usr_paths will not be updated.
And of course, this field cannot be accessed directly, so our last resort is to use reflection :
Field usrPathFiled = ClassLoader.class.getDeclaredField("usr_paths");
usrPathFiled.setAccessible(true);
String[] usrPath = (String[]) usrPathFiled.get(null);
String[] newUsrPath = new String[usrPath.length + 1];
System.arraycopy(usrPath, 0, newUsrPath, 0, usrPath.length);
newUsrPath[usrPath.length] = destFile.getParentFile().getAbsolutePath();
usrPathFiled.set(null, newUsrPath);

By executing this code before using the jar that will load the native library, we have a programmatic 100% Java workaround to our problem.

It's definitely not the most beautiful way of coding in Java, some of you might say "If it's private in the JDK, there is a good reason, Son !"
Anyway, shall this article avoid other people to waste their time on this problem.