Module 3 Task 1: Retrieving Media Using Web Services


Launch JavaFX Media Browser Application Download NetBeans Project

Introduction

This task uses the Web Services API to search for media using the Yahoo! Search service.

Running the Project

  1. Download the Module 3 Task 1 NetBeans project

  2. Run the project.

The functionality is the same as in previous tasks. The only difference is that the data is obtained with internet search. Figure 1 shows the result.

The application search query is predefined to be "Sun Microsystems", and a maximum of 50 objects are found. In a future project you will create a search text box so users can enter a search query.

Wall with default search and scroll control Figure 1

Architecture

For the first time this tutorial assembles metadata from search results. This requires two new classes, YahooAPI.fx and WebSearch.fx, as shown in Figure 2.

  • The new YahooAPI.fx class is a "custom" class created to interface with the Yahoo! API. Typically you create a custom class such as this for each Web Services API you use.

  • WebSearch.fx uses javafx.io.http.HttpRequest to send an HTTP GET request to the web service API and javafx.data.pull is used to parse the response. WebSearch handles the interaction between javafx.data.pull and javafx.io.http.HttpRequest.

Architecture for Module 3 Task 1 Figure 2

Using Yahoo! Web Services

In this application you search the web with Yahoo! services. To do this you construct a Representational State Transfer query (REST). You can read about the query format for the Yahoo APIs at http://developer.yahoo.com/search/image/V1/imageSearch.html.

Look at Figure 2 to get an idea of what you need to do to make this work.

Being familiar with the API for javafx.data.pull and javafx.io.http will help you understand this task. Consult the API documentation which has excellent examples of how the API is used.

WebSearch creates the input stream that handles the GET request. The HttpRequest onInput variable is implemented to call the PullParser's parse() function. The PullParser's onEvent function is implemented to call the WebSearch API's abstract function onPullEvent(). is implemented in the concrete class YahooAPI. As YahooAPI's implementation of onPullEvent processes events from the PullParser, new MetaData objects are created and inserted into the WebSearch results var. In Wall, the metaData variable is bound to WebSearch.results. The following sections examine these steps in greater detail.

Updating MetaData.fx

In this task the MetaData sequence is bound to the Yahoo search results. The data model includes the response fields that are useful in this application. The public classes Thumb and MetaData form the responses into URLs. Thumb encapsulates the web search results data that corresponds to the thumbnail image. For example, the thumbnail URL. MetaData encapsulates those parts of the web search results that are of interest to the application. For example, the media URL and the Thumb data. This application doesn't use all of this information, but it is worth exploring.

Using HttpRequest to Get the Input Stream

WebSearch handles the GET request that fetches results for the search. It uses a local instance of HttpRequest to send the request. When the response to the request comes back, HttpRequest calls the onInput function, if it is defined. In the instance of HttpRequest in WebSearch.fx, the onInput() function is defined to call the PullParser's parse method, which parses the input stream.

HttpRequest calls onInput when the input stream response is ready. By providing a function for onInput you can tell the parser to parse the input stream.

As PullParser parses the input stream, the parser calls the onEvent function of the PullParser instance when the start or end of an element is encountered. In WebSearch, the onEvent variable is bound to an abstract WebSearch function onPullEvent(). Because the method is abstract, it must be implemented in a class that extends from WebSearch. In this case, that class is YahooAPI.

Source Code
def pullParser = PullParser {

        documentType: PullParser.XML;

        // Forward events to the YahooAPI onPullEvent function
        onEvent: onPullEvent
    }

The HttpRequest has a location variable, which is the URL of the search API. This is bound to the searchLocation variable in WebSearch. By overriding searchLocation in YahooAPI, you effectively set the location for HttpRequest.

Source Code
    /** Refer to the javadoc for javafx.io.HttpRequest */
    def httpRequest : HttpRequest = HttpRequest {

        method: HttpRequest.GET

        location: bind searchLocation

        onResponseMessage: function(msg:String) {
            if ( httpRequest.responseCode != 200 ) {
                println("HTTP response {httpRequest.responseCode}: {msg}");
            }
        }

In addition to location, the other thing you need is a search query. WebSearch declares a searchQuery variable for this purpose. Notice that YahooAPI overrides searchQuery. In YahooAPI, if the searchQuery changes, the searchLocation is updated. Thus, when the search() function is executed, the HttpRequest's location variable will have the correct URL for the query.

Source Code
onInput: function(is: InputStream) {
            try {
                pullParser.input = is;
                pullParser.parse();
            } finally {
                is.close();
            }
        }

The code above sets pullParser.input to the input stream coming back from this function, and calls pullParser.parse. The pullParser parse method starts the parser working , calling onEvent as it encounters events.

Building the REST Query for Yahoo Image Search

YahooAPI.fx extends WebSearch.fx to create the REpresentational State Transfer (REST) query.

The variables searchLocation and searchQuery both override the WebSearch base class definition. You cannot redefine base class variables — they must be overridden. The variable should be a well known attribute that all APIs use, so searchQuery is used here. The 'on replace' trigger for searchQuery replaces all spaces with the + character (denotes include).

Source Code
    override var searchQuery on replace {
        yahooSearchQuery = searchQuery.trim().replaceAll(" ","+");
    }

onPullEvent is the abstract function from WebSearch.fx that you are overriding. Again, you must override the base class variables because they cannot be redefined. onPullEvent() looks for PullParser.START_ELEMENT and PullParser.END_ELEMENT, dispatching starts to processStart() and ends to processEnd().

Source Code
override function onPullEvent(event : Event) : Void {
        if (event.type == PullParser.START_ELEMENT) {
            processStart(event)
        } else if (event.type == PullParser.END_ELEMENT) {
            processEnd(event)
        }
    }

The javafx.data.pull.Event level is important because XML elements can be nested. The XML root element, for example, is at level 0. Result is a top level event whose level is 1. Thumbnail is nested in the Result element so its event level is 2.

processEnd() is called when you encounter an PullParser.END_ELEMENT. If the tag is Result you have a complete piece of metadata. You can put result into the results Sequence, causing the results to be pushed to the wall:

Source Code
if ("Result".equals(event.qname.name) and event.level == 1) {
            insert result into results;

Calling Search and Getting MetaData

This section describes how search data becomes available for display.

In Wall.fx, metaData is simply bound to the WebSearch results (metaData no longer needs to be package accessible, so the package keyword isn't necessary):

Source Code
var metaData : MetaData[] = bind webSearch.results;

In Main, webSearch is bound to an instance of the YahooAPI. Also in Main, a WebSearch object is created as follows:

Source Code
def yahoo : WebSearch = YahooAPI {
    searchQuery: "Sun Microsystems"
}

In effect, webSearch is a Yahoo instance.

Later on in Main, the default search uses the Yahoo instance:

Source Code
yahoo.search();

WebSearch.fx contains the search function, which simply queues the httpRequest:

Source Code
    package function search() {
            httpRequest.enqueue();
    }

In YahooApi, processEnd() inserts metadata into the WebSearch results sequence, which is bound to metaData in Wall. In Wall, the thumbnails sequence is also bound to metaData, but in a way that causes a new Thumbnail instance to be created as MetaData is inserted. Thus, MetaData from the WebSearch ends up as Thumbnails on the Wall.

Source Code
insert result into results

Metadata comes from web search results and is available to populate the wall.

Try It

  • The standard Sun Microsystems search happens to yield all JPEGs. To see a different format, go to YahooAPI and set yahooSearchQuery to png or some other supported format.

  • To see how the pull parser works, print out the event in the onPullEvent code in YahooAPI and also print out the MetaData before it is inserted in the results sequence in YahooAPI.

    • After the onPullEvent if/else-if statement, insert:
      javafx.lang.FX.println("pullParser event: {event}");

    • Before insert result into results, enter this line:
      println("insert {result}");

Rate This Article
Discussion

We welcome your participation in our community. Please keep your comments civil and on point. You may optionally provide your email address to be notified of replies—your information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.

 

English
日本語
한국어
简体中文
русский
Português do Brasil