Skip to main content

Creating mashups with JavaFX

Michael Galpin (mike.sr@gmail.com), Software architect, eBay
Michael Galpin's photo
Michael Galpin has been developing Web applications since the late 90s. He holds a degree in mathematics from the California Institute of Technology and is an architect at eBay in San Jose, CA.

Summary:  Are you a Java™ developer who wants to leverage the open Web to create Rich Internet Applications (RIAs)? You are in luck. Now JavaFX empowers developers to leverage the Java platform to create RIAs. In this article, learn how you can use JavaFX to create mashups. See how JavaFX lets you tap into popular Web services such as Flickr and how you can use it to create interactive user interfaces. Along the way, get a taste of the new capabilities that JavaFX brings to client-side development.

Date:  10 Feb 2009
Level:  Intermediate PDF:  A4 and Letter (250KB | 14 pages)Get Adobe® Reader®
Activity:  9536 views

Getting started

In this article you will use JavaFX to develop a Rich Internet Application (RIA). JavaFX is not just a new technology for creating RIAs, but it is also a new programming language. It borrows heavily from the Java language and runs on the Java Virtual Machine. You do not have to be an expert Java programmer to create a JavaFX application, but familiarity with Java is helpful. You will need the JavaFX SDK; Version 1.0 of the JavaFX SDK was used to develop the code in this article. You will also need a Java Development Kit; JDK 1.6.0_07 was used to compile and run the code in this article. See the Download table for download links.

A JavaFX model

Explore JavaFX by developing a typical mashup application. The application will use a Web service from the popular photo sharing site Flickr. You will search Flickr for photos and display them in the JavaFX application. To start, you will model the data from the Flickr Web service using JavaFX.

Modeling in JavaFX

Flickr offers RESTful Web services that can be called from any code, including JavaFX code. Calling the Flickr's services requires an API key that you can obtain for free from Flickr. It is possible to specify the format of the response from Flickr. The default is XML, and that is what will be used in this application. Sample output is shown in Listing 1.


Listing 1. Sample Flickr XML
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="132147" perpage="6" total="792880">
     <photo id="3196302982" owner="14994333@N08" secret="7c4e209fe9" 
server="3536" farm="4" title="Pond" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="3196288734" owner="19764560@N00" secret="5142dd0a2d" server="3514" 
farm="4" title="Pull In Case Of Fire" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="3195451611" owner="25304693@N00" secret="4ef1d2b63d" server="3528" 
farm="4" title="Domein Nieuwenhoven" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="3196281786" owner="51865294@N00" secret="bed01bff0c" server="3403" 
farm="4" title="Uitdam skyline" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="3196281752" owner="27734999@N03" secret="a81c2e53a5" server="3301" 
farm="4" title="IMG_7642" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="3196281596" owner="51865294@N00" secret="c0f18f3aef" server="3510" 
farm="4" title="Warm scene on a cold day" ispublic="1" isfriend="0" isfamily="0" />
</photos>
</rsp>

As you can see from Listing 1, each photo has several attributes that are important: id, secret, server, farm, and title. The first four of those are needed to create the URL of the image. Modeling this object using JavaFX is straightforward and is shown in Listing 2.


Listing 2. A Flickr image model in JavaFX
public class FlickrImage{
    var id:String;
    var secret:String;
    var server:String;
    var farm:String;
    var title:String;

    public function getUrl():String{
        "http://farm{farm}.static.flickr.com/{server}/{id}_{secret}.jpg"
    }
}

This simple class demonstrates several aspects of JavaFX's syntax. The keyword var is used to denote an instance variable in JavaFX. As you will see later, each of the vars in the class declaration becomes a named parameter when constructing an instance of the class. Notice that JavaFX is statically typed, with the type declared as a suffix to the variable's name.

The class also has a single method, getUrl. Methods are declared as functions in JavaFX, and they are also statically typed. JavaFX has a return keyword that works just as you would expect, but it is optional. It has been omitted in Listing 2, so the last line of the function will be returned. In this case it is a string expression. JavaFX will insert the instance variables into the place holders in the string denoted using curly-braces. Note that this is statically typed. So if you misspelled "secret" in the above example, or tried to call a method on it that did not exist, you would get a compile-time error.

Notice in Listing 2 that the vars have no access control modifiers. The default for JavaFX is script-private, so they will not be accessible from other classes. The lone method is declared as public, so it will be available to other classes. Now that you have a class to model images from Flickr, you just need a way to get some data to stuff into these classes. For that you will need to call the Flickr Web service.

Calling a Web service

JavaFX applications can make remote calls to Web services. The javafx.io.http package contains classes for asynchronously calling Web services. These classes in turn rely on Java's networking stack. This is an important difference between JavaFX and other RIA technologies that rely on the Web browser to make remote calls. Given that, here is the sample application's model that accesses Flickr's Web service for data (shown in Listing 3).


Listing 3. Model with data access code
var pics:FlickrImage[] = [];

public class Model {
    public var tag:String;
    public var onSuccess: function(FlickrImage[]):Void;

    public function searchFlickr(){
        delete pics;
        var url=
            
"http://api.flickr.com/services/rest/?method=flickr.photos.
search&per_page=6&api_key={API_KEY}&tags={tag}";
        var req = HttpRequest{
            location : url
            onInput: function(stream:InputStream){
                parser.input = stream;
                parser.parse();
                onSuccess(images);
            }
        }
        req.enqueue();
    }
    
    def API_KEY = "Put Your API Key Here";
    var images:FlickrImage[] = bind pics;
}

This code demonstrates several more key features of the JavaFX language. The Model class has two public vars. One of these is a simple string called tag. This is the tag that will be used for the search query to Flickr. The other public var, onSuccess, is a function. Functions are first class objects in JavaFX. The declaration for onSuccess states that it is a function that takes an array of FlickrImage objects as an input parameter and returns nothing (Void.) Any function passed in to this parameter must satisfy this signature, or you will get a compiler error.

These two public vars are both used in the public function searchFlickr. Here you use the HttpRequest class to make a call to the Flickr Web service. Notice the syntax for creating an instance of HttpRequest. This is the declarative syntax of JavaFX. In this case you are passing in two named parameters to the constructor of HttpRequest. One is a string called location, and the other is a function called onInput. Parameter name/value pairs are denoted by name : value. So for the onInput parameter, you create an anonymous function. The static typing of JavaFX allows you to know that onInput takes a function that takes a java.io.InputStream as its sole input parameter and has a Void return type. The onInput method above in Listing 3 passes the InputStream to a parser object and then invokes the onSuccess method that gets passed into the Model instance. Finally, after constructing the HttpRequest, you invoke its enqueue method. This tells the JavaFX runtime to invoke the method as soon as it has a free thread to do so. Do not use the main application thread to make a remote call, as this would cause the application to become unresponsive while you wait on the remote server.

Before moving on to the parser code, you may have noticed a few more things in the Model class and its searchFlickr method. It has an array (sequence) of FlickrImage objects called images. These are bound to a script-level array called pics. Data binding is an important part of JavaFX that allows one object to be changed, and those changes are then propagated to other objects. In this case, any changes to pics will be propagated to images. The very first line of the searchFlickr method uses the JavaFX keyword "delete" to clear the data out of the pics sequence. Finally, notice how the API_KEY is declared as a def. This essentially makes it a constant. Now we have covered everything in the Model class, so we are ready to move on to parsing the data that comes back from Flickr.

XML parsing in JavaFX

Back in Listing 3 you saw a parser being referenced, and you saw a java.io.InputStream being passed to it. Mixing core classes from Java with JavaFX is very common. In this case you are passing the InputStream to a javafx.data.pull.PullParser. This is similar to a StAX parser in Java. It allows you to receive a stream of events from the parser, similar to SAX-style parsing, but with the ability to control the flow of events, by only "pulling" the ones you want. JavaFX's PullParser works equally well with both XML and JSON data—the two most common formats for Web services. This makes JavaFX well suited for mashups like the one being created in this article. Listing 4 shows the code for parsing the XML from Flickr.


Listing 4. Parsing XML in JavaFX
def ID = QName {
    name : "id"
}
def SECRET = QName{
    name : "secret"
}
def SERVER = QName{
    name : "server"
}
def FARM = QName{
    name : "farm"
}
def TITLE = QName{
    name : "title"
}

def parser = PullParser{
    documentType : PullParser.XML
    onEvent : function(event:Event){
        if (event.type == PullParser.START_ELEMENT){
            if (event.qname.name.equals("photo")){
                var image = FlickrImage{
                    id : event.getAttributeValue(ID)
                    secret : event.getAttributeValue(SECRET)
                    server : event.getAttributeValue(SERVER)
                    farm : event.getAttributeValue(FARM)
                    title : event.getAttributeValue(TITLE)
                }
                insert image into pics;
            }
        }
    }
}

The first thing you will notice in the code in Listing 4 is that we define several QName objects. These are qualified names in XML terminology, and they represent the qualified names of attributes in the XML coming back from Flickr. As you would expect, JavaFX's QName class allows for a namespace and a prefix, as well as the name. The Flickr XML (Listing 1) does not use namespaces, so all you need is a simple name for the QNames in Listing 4.

The PullParser instance is created using JavaFX's declaration syntax. This should start looking familiar! In Listing 4, you simply indicate that you are parsing XML by setting the documentType property. You then pass in an anonymous function (closure) to the onEvent property. You simply look for a START_ELEMENT event, and then if the element is "photo", you pull out the data from its attributes and use this to create a new FlickrImage instance. You need to add this instance to the pics sequence. Notice how this is done using the JavaFX reserved word insert. This will always add to the end of the sequence. Finally you should note that all of the QNames and the PullParser are defined as defs (in other words, constants). You could make them vars as well, but it is more correct to have them as defs. This is similar to declaring them as final in Java.

Now we have looked at all of the data handling code. You have seen how to invoke a remote Web service and how to parse the XML that it returns. It is time to move on to the more glamorous user interface code that JavaFX is more well known for.


Eye candy with JavaFX

When JavaFX was first introduced at JavaOne in 2007, it was billed as a technology for creating rich user experiences. The UI aspects of JavaFX have always been stressed, so it should come as no surprise that JavaFX really shines in this area. Take a look at the user interface of our mashup. We will start by seeing how easy it is to extend some of the core classes in JavaFX.

Extending JavaFX

The application needs to show images from Flickr, so you need JavaFX's Image and ImageView classes. The workflow is straightforward. Use a FlickrImage object to calculate the URL of the image, create an Image instance using that URL, and then create an ImageView object using that Image. The ImageView object can then be added to a Scene (more on that later.) Let's encapsulate that logic with a new class as shown in Listing 5.


Listing 5. A FlickrView
public class FlickrView extends ImageView{
    public var flickrImage:FlickrImage;
    init {
        this.image = Image { 
            url : flickrImage.getUrl()
        }
    }
}

As you can see, the FlickrView class is a subclass of ImageView. It adds a new var, flickrImage. The init method is akin to a constructor in Java. It is called immediately after all of the vars have been set by the caller. In this case it uses the FlickrImage instance to create an Image instance using the URL calculated by the FlickrImage. Subclassing is straightforward in JavaFX; it is just like Java. Constructors are also easy using the init block. With the FlickrView, it will be easy to display images from Flickr, so you are ready to create the rest of the user interface.

Crafting the user interface

So far you have seen JavaFX's declarative style of syntax used in many places to construct new objects. This can be very convenient for developers. If you have done much JavaScript programming, then this style of programming is very familiar. It really comes into its own when you are creating the user interface. The main user interface of the application is shown in Listing 6.


Listing 6. User interface code
Stage {
    title: "FlickrFX"
    width: 500
    height: 500
    scene: Scene {
        fill: LinearGradient {
            startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
            proportional: true
            stops: [ Stop { offset: 0.0 color: Color.ORANGE },
                     Stop { offset: 1.0 color: Color.BLUE } ]
        }
        content: VBox{
            spacing : 50
            content : [
                HBox {
                    spacing : 20
                    content : bind topRow
                },
                HBox{
                    spacing : 10
                    content : [
                        Text {
                            font: Font {
                                size: 24
                            }
                            x: 10,
                            y: 30
                            content: "Tag"
                        },
                        input,
                        SwingButton {
                            text: "Search"
                            action: function() {
                                var model = Model {
                                   tag : input.text
                                   onSuccess : displayImages
                                }
                                model.searchFlickr();
                            }
                        }
                    ]

                },
                HBox {
                    spacing : 20
                    content : bind bottomRow
                }
            ]
        }
    }
}

This code in Listing 6 may look a bit daunting at first, but it is actually quite straightforward. Let's start at the top. The Stage is the main display window of the application in this case. The code constructs a new javafx.stage.Stage instance. It sets the Stage instance's title var to FlickrFX and sets its height and width vars to 500. If you stopped here, the application would look like Figure 1.


Figure 1. Bare bones JavaFX application
Bare bones JavaFX applicatoin

This application isn't very interesting, but you get the idea. The next thing that the code does is set the Stage instance's scene var. It sets this to a new instance of the javafx.scene.Scene class. The first thing that happens for the Scene is to create a background fill. In this case it creates a gradient fill by setting the value of the Scene instance's fill var to a new instance of javafx.scene.paint.LinearGradient. The gradient starts with orange on top and finishes with blue on the bottom. LinearGradient's startX, startY, endX, and endY determine where the gradient starts and ends. This gradient will be vertical because startX and endX are the same, but startY and endY goes from 0.0 to 1.0. Finally the LinearGradient's stops var is set to an array of javafx.scene.paint.Stop objects. This is how you set where to start the orange and blue. With the gradient code in place, the application now looks like Figure 2.


Figure 2. Bare bones application with gradient
Bare bones application with gradient

Well at least you have some color now! The only other thing you set on the Scene instance is its content var. Set this to a javafx.scene.Node object. Node is an abstract class that is the base class of all graphical objects in JavaFX. In this case you construct a javafx.scene.layout.VBox instance. The VBox is a container, and it will lay out its contents in a vertical fashion from top to bottom. We set its spacing var to 50, so it will put 50 pixels between each object that it contains.

Objects are added to the VBox by putting them into a sequence of Nodes that are set to the VBox's content var. In this case you construct three javafx.scene.layout.HBox instances. As its name suggests, HBox is similar to VBox, but it lays out its contents horizontally, from left to right. Thus by stacking three HBox instances inside a VBox, you get a flexible grid.

The top and bottom HBox instances are bound to two other script variables, topRow and bottomRow. Again you have used JavaFX's powerful binding constructs. Whenever topRow or bottomRow are changed, the HBox instances will be changed, and thus those parts of the user interface will be refreshed. So what do you put in topRow and bottomRow? That code is shown in Listing 7.


Listing 7. Top and bottom row of the grid
def LOGO = Image {
    url: "http://lh3.ggpht.com/_XmwdENwf53s/SW06N4aWEDI/AAAAAAAAAgo/
nXzkz7IBEnk/javafx.png"
}

var topRow = for (i in [1..3]) {
    ImageView{
        image: LOGO
        fitWidth : 150
        fitHeight : 150
        preserveRatio: true
        smooth: true
        cache: true
    }
}
var bottomRow = for (i in [1..3]) {
    ImageView{
        image: LOGO
        fitWidth : 150
        fitHeight : 150
        preserveRatio: true
        smooth: true
        cache: true
    }
}

Here we have used another useful feature in JavaFX. The topRow and bottomRow vars are constructed using a loop expression (technically a list comprehension). This is a nice feature of JavaFX. The equivalent Java code would not only be more verbose, but it would be less obvious what it was doing. In this case, JavaFX's syntax makes it obvious that you are creating a sequence of ImageView instances, where each ImageView instance uses the constant Image instance called LOGO.

So that covers the top and bottom rows of the grid, but what about the middle row? From Listing 6, you can see that it creates a label (an instance of javafx.scene.text.Text) that says "Tag" and a button. Actually the button is an instance of javafx.ext.swing.SwingButton. JavaFX leverages many of the objects in Swing, but it makes them easier to use thanks to its convenient syntax. The button says "Search", and its action var is set to a closure. We will look at that in more depth in the next section. Finally, the middle row also references another script variable called input. This is created explicitly so that it can be referenced in other parts of the code (namely in the button's action closure.) For completeness, its code is shown in Listing 8.


Listing 8. The input control
def input = SwingTextField {
    columns: 10
    editable: true
}

Similar to the button, this is also a Swing-based control. In this case it is an instance of javafx.ext.swing.SwingTextField. Note that it is once again a def, so that it cannot be mutated. Now that you have all of the controls in place, let's take a look at what the application looks like. It is shown in Figure 3.


Figure 3. Initial UI complete
Initial UI complete

Now all of the UI elements are in place. You are ready to hook up the view to the model created earlier. You will need some controller code to glue everything together and make this RIA interactive.


Gluing it together: JavaFX controls

Back in Listing 6, you saw that we had a button whose action var was set to an inline function. Let's take a closer look at that now. The function creates a Model instance (Listing 3) passing in the value of the text var from the input object, and a reference to another function called displayImages. The Model instance's searchFlickr method is then invoked. From Listing 3, you know that this displayImages function will be invoked once the remote call to Flickr has completed and the results have been parsed into FlickrImage objects. Take a look at the displayImages function in Listing 9.


Listing 9. Displaying images from Flickr
function displayImages(images:FlickrImage[]){
    delete topRow;
    delete bottomRow;
    for (i in [1..3]){
        insert FlickrView {
            flickrImage : images[i-1]
            fitWidth : 150
            fitHeight : 150
            preserveRatio : true
            smooth : true
            rotate : 60*(i-2)
        } into topRow
    }
    for (i in [1..3]){
        insert FlickrView {
            flickrImage : images[i+2]
            fitWidth : 150
            fitHeight : 150
            preserveRatio : true
            smooth : true
            rotate : -60*(i-2)
        } into bottomRow
    }
}

JavaFX lets you write some fairly succinct code. The function deletes the topRow and bottomRow, clearing out whatever Nodes are in those sequences. It then uses JavaFX's for loop to iterate through the images object. For each FlickrImage instance, a FlickrView instance is created and, using JavaFX's insert statement, added to topRow or bottomRow. You might also notice that each FlickrView instance has its rotate var set as well. This is a var from Node (thus any graphical object can be rotated). It takes a rotation in degrees to apply to the Node. This gives you a fancy treatment for each image, as shown in Figure 4.


Figure 4. Showing images from Flickr
Showing images from Flickr

Keep in mind that the search results will change over time, even for "toast". If you look back at Listing 8, you will see that each image has its fitWidth and fitHeight vars set to 150, and the preserveRatio var is set to true. You can see the results in Figure 4. The JavaFX runtime dynamically resizes the images. The height and width are maxed out at 150 pixels, but the ratio of the height-to-width is preserved so the images are not distorted.


Summary

In this article, you have built a mashup using JavaFX. The mashup demonstrates how to invoke remote Web services and how to parse data coming from remote services. You have seen how to create a user interface using JavaFX and how to wire together controller logic to the user interface elements. These are some of the most common tasks in creating a mashup, and you have seen how JavaFX is designed to make these tasks easy. Along the way you have also seen examples of the important features of JavaFX's syntax: its type system, its support for closures, it sequence syntax, its powerful data binding, and its declarative syntax for constructing objects. Now you should be ready to create your own JavaFX-powered mashup.



Download

DescriptionNameSizeDownload method
Mashup source codeFlickrFX.zip3KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

  • JavaFX: This article uses JavaFX 1.0.

  • Java SDK: This article uses Java SE 1.6_05.

  • IBM trial software: Innovate your next open source development project with IBM trial software, available for download.

  • Download IBM product evaluation versions: Get your hands on application development tools and middleware products from DB2, Lotus, Rational, Tivoli, and WebSphere.

Discuss

About the author

Michael Galpin's photo

Michael Galpin has been developing Web applications since the late 90s. He holds a degree in mathematics from the California Institute of Technology and is an architect at eBay in San Jose, CA.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=368781
ArticleTitle=Creating mashups with JavaFX
publish-date=02102009
author1-email=mike.sr@gmail.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers