Posts Tagged json
JavaFX asynchronous communication with JSON and REST based web services
Posted by Sébastien Stormacq in Java on 19/01/2009
While writing Rich Internet Application with JavaFX is relatively easy and well documented, fetching data from remote sources seemed more obscure to me. The documentation is minimal and I did not found any good tutorial describing the various techniques available to connect to a remote web service and how to parse the results.
While this blog entry do not aim at being such a tutorial, I will just give an example I developed over the week end to integrate a JSon based REST web service from a JavaFX application.
(For those of you interested in database access, my colleague Octavian just published a blog entry on the subject).
Let’s first start with the REST web service. Once you have installed the appropriate plugin into NetBeans, it is as simple as creating a web application, then creating a REST based web service.
I used the json.org supplied JSon Java classes to create the output message.
The web service I created just return 4 random values, between 0 and 100. The syntax of the returned message is
{“Values”: 21, 35, 76, 82}
And the code is as follow :
@Path("values") public class ValuesResource { Random rand = new Random(new java.util.Date().getTime()); @GET @Produces("application/json") public String getValues() { String result; try { result = new JSONStringer() .object() .key("Values") .array() .value(rand.nextInt(100)) .value(rand.nextInt(100)) .value(rand.nextInt(100)) .value(rand.nextInt(100)) .endArray() .endObject().toString(); } catch (JSONException e) { e.printStackTrace(); result = "{ \"error\" : \"" +e.getLocalizedMessage() + "\" }"; } return result; } }
I deployed this on GlassFish v3 and tested from command line with curl :
marsu:~ sst$ curl http://localhost:8080/WebApplication1/resources/values {"Values":[94,61,26,72]}
In my JavaFX application, I want to call this web service on a regular basis. I therefore choose to use the Timer and TimerTask Java classes to wrap the calling code and execute it on a regular time-based interval.
The first piece of code is a custom TimerTask. It wraps the JavaFX provided RemoteTextDocument, a very easy to use class that wraps the HTTP communication.
var values : Number[]; class Task extends TimerTask { override function run() { var request : RemoteTextDocument = RemoteTextDocument { url: "http://localhost:8080/WebApplication1/resources/values"; } var returnValue: String = bind request.document on replace { if (request.done) { var data : JSONArray = new JSONObject(returnValue).getJSONArray("Values"); for (i in [0..data.length() - 1]) { insert data.getDouble(i)into values; } } } } };
The RemoteTextDocument as three useful attributes :
-
url, the URL to connect to ;
-
done, a flag indicating that the connection is completed ;
-
document, the text returned by the URL connection
The URL connection is made automatically when creating an instance of the class.
To get access to the document in an asynchronous way, I am using the bind and on replace capabilities provided by JavaFX.
My returnValue variable is bound to request.document, meaning that every time request.document is modified, returnValue is updated to reflect the new value.
The on replace trigger, allows to execute some code when the value of returnValue is changing, basically, it parses the resulting String with the Java based JSon classes and create an array of Number.
Easy to write, to read and very efficient !
The last step is to create a Java Timer to trigger the TimerTask on a regular basis. I want this process to start as soon as the JavaFX application starts. JavaFX does provide a run() function for this purpose.
function run( args : String[] ) { def timer : Timer = new Timer("TimerThread"); def task : Task = new Task(); //run the TimerTask immediately and every 5 secs timer.schedule(task, 0, 5000); //more JavaFX line of code, notably create the Stage and Scene etc ... }
Et voila … the JavaFX application will start polling the REST web service every 5 secs. I further bounded the array of Number prepared by the TimerTask to a PieChart component. The net result is a self-refreshing pie chart as shown below. The PieChart JavaFX component will be described in a later blog entry. |
|