A JavaFx Planetary Kp barchart applet - Part 3

This article discusses the code to retrieve Planetary Kp data from a drupal webservice.  Previously in Part 1 was a discussion of Planetary Kp data itself. Part 2 was a discussion of the code to create a bargraph to display the data.

A couple classes are defined to represent the data to be retrieved.  The first is called SpaceWeatherData which is a container for the time series data. Class variables start and end are used to store the start and end times of the data retrieved. The variable dataType is used to represent the type of data contained is in this case equal to  "Kp".
 The variable vals is an array containing TimeSeriesData

/*
 * SpaceWeatherData.fx
 * @author Vern Raben
 * Created on Dec 15, 2009, 4:16:28 PM
 * For license terms and conditions see license.fx in this package.
 */

package kpchart;

public class SpaceWeatherData {
    public var start:String;
    public var end:String;
    public var dataType: String;
    public var vals: TimeSeriesData [];
    public var duration: String;
}

TimerSeriesData is used to represent the Planetary Kp values as well as other types of space weather time series data. It consists simply of a date, the name, and a value. 

/*
 * TimeSeriesData.fx
 * Define a TimeSeriesData class
 * @author: Vern Raben
 * Created on Nov 19, 2009, 11:57:41 AM
 */

package kpchart;

/**
 * @author Vern Raben
 */

public class TimeSeriesData {
    public var date: String;
    public var name : String;
    public var val: Number;
}

Next up is discussion of the class that actually retrieves the data from a space weather restfull interface, SpaceWeatherRetriever. (I'd guess that object-oriented purists will shutter at the concept, but I've always done it this way through the years.... I have no justification other than convenience).

It consists mainly of a method that goes out and gets JSON encoded data from a RESTful spaceweather webservice. The JSON data received resembles the  following structure:

{"dataset":"kp_afwa_3hr", "duration":"1d", "end":"2010-04-04", "start":"2010-04-04 00:00:00",
 "vals":[
 {"date":"2010-04-04 00:00:00","name":"kp","val":"30"},
 {"date":"2010-04-04 03:00:00","name":"kp","val":"30"},
 {"date":"2010-04-04 06:00:00","name":"kp","val":"40"},
 {"date":"2010-04-04 09:00:00","name":"kp","val":"10"},
 {"date":"2010-04-04 12:00:00","name":"kp","val":"20"},
 {"date":"2010-04-04 15:00:00","name":"kp","val":"20"},
 {"date":"2010-04-04 18:00:00","name":"kp","val":"30"},
 {"date":"2010-04-04 21:00:00","name":"kp","val":"40"}
 ]
 }

 

The URL of the webservice is defined in the constant "SWD_URL".  Most of the code is concerned with parsing variables in the JSON markup (lines 43 thru 103) . A new TimeSeriesData object is created when  the parser encounters a new JSON element (lines 51 to 54).  The TimeSeriesData is inserted the SpaceWeather array when the end of the element is detected (lines 55 to 58). The space weather data attributes ("dataset", "start", and "end") are set as the event is received (lines 63 to 84).  Similarly,   time series data attributes ("date", "name", and "val") are set as corresponding event is received (lines 85 to 99).

 

    /**
     * Retrieve space weather data and update chart
     * @param dataSet: name of dataset
     * @param endDate: date to be retrieved (yyyy-mm-dd)
     * @param duration: time span of data to be retrieved d=day h=hour
     * for example 5d = 5 days of data starting at 0:00 UT 5 days prior to endDate
     */
    public function updateSWD(dataSet:String, date:String, duration:String)
    {
        var tsd:TimeSeriesData;
        var url = "{SWD_URL}/{dataSet}/{date}/{duration}";
        httpRequestError = false;

        var request: HttpRequest = HttpRequest
        {
            location: url;
            method: HttpRequest.GET,
            onInput: function(is: java.io.InputStream) {

                try
                {
                    def parser = PullParser
                    {
                        documentType: PullParser.JSON
                        input: is

                        // Handle events triggered for each node
                        onEvent: function(event: Event) {

                            if (event.type ==PullParser.START_ELEMENT)
                            {
                                tsd = TimeSeriesData{};
                            }
                            else if (event.type ==PullParser.END_ELEMENT)
                            {
                                insert tsd into swd.vals;
                            }

                            else if (event.type ==PullParser.TEXT)
                            {
                                if (event.level == 0)
                                {
                                    if (event.name == 'dataset')
                                    {
                                        swd.dataType = event.text;
                                    }

                                    if (event.name == 'end')
                                    {
                                        swd.end = event.text;
                                    }

                                    if (event.name == 'start')
                                    {
                                        swd.start = event.text;
                                    }

                                    if (event.name == 'duration')
                                    {
                                        swd.duration = event.text;
                                    }

                                } 
                                else if (event.level == 1)
                                {
                                    if (event.name == 'date')
                                    {
                                        tsd.date = event.text;
                                    } 
                                    else if (event.name == 'name')
                                    {
                                        tsd.name = event.text;
                                    } 
                                    else if (event.name == 'val')
                                    {
                                        tsd.val = Double.valueOf(event.text);
                                    }
                                }
                            }
                        }
                    }
                    parser.parse();
                }
                finally {
                    is.close();
                }
            }
            // Update chart after data is retrieved
            onDone: function()
            {
                if(not httpRequestError)
                {
                    Main.updateChart(swd);
                }
            }

            // Report any exceptions
            onException: function(exception: java.lang.Exception)
            {
                httpRequestError = true;
                Alert.inform("Error occurred while retrieving data from web service. ");
            }

            // Response code handler, for all but 200 (OK)
            onResponseCode: function(responseCode:Integer)
            {

                if (responseCode != 200)
                {
                    httpRequestError = true;
                    Alert.inform("Request to web service at url {SWD_URL} failed. Response code was: {responseCode} with {request.responseMessage}");
                }

            }

        }

        request.start();

    }

After the data is received and parsed, the Kp chart is updated (line 114).

Error handling is pretty simplistic (ie needs improvement). An Alert dialog is popped up if there is an http code other than 200 is recieved (lines 129 to 133).

In the next article I'll discuss the drupal module that implements the space weather service which provides the Planetary Kp data.