Posted by
arungupta on December 4, 2008 at 7:12 AM PST
Today Sun announces the availability of
Java
FX 1.0.
JavaFX 1.0 is a rich client platform for creating and delivering
Rich
Internet Applications across all screens (desktop, browser,
and mobile) of your life. It consists of the following key components:

|
- JavaFX
SDK includes JavaFX script compiler and runtime
tools, and a host of libraries to create RIAs for desktop, browser and
mobile platforms, command-line tools & Ant tasks and other
goodies.
- NetBeans
6.5 support (as plugin or bundled with IDE) that allows to
build, preview and debug JavaFX applications using NetBeans IDE. If you
prefer CLI support then SDK can be downloaded.
- Production
Suite is a suite of tools and plugins for creative tools
(such as Illustrator CS3+) that allows graphical assets to be
exported to JavaFX applications.
|
The beauty of JavaFX is that its fully integrated with the Java Runtime
and takes advantage of the performance and ubiquity of Sun's Java
Runtime Environment that is installed on literally billions of devices
worldwide. Hence, JavaFX applications will run on any desktop, browser,
mobile device or any other connected device that runs the Java Runtime
Environment.
 |
This blog shows how to create a simple JavaFX
application using NetBeans
IDE. The application plays a movie, allows the
viewer to cast a vote if they liked it, and see aggregate response from
other viewers. The application is developed using NetBeans 6.5, JavaFX
1.0 plugin, and coded using JavaFX Script. The voting engine
is deployed as a RESTful Web service using Jersey on GlassFish. |
In terms of
user experience, running the NetBeans project shows a window playing
the movie. The first mouse hover over the window allows the viewer to
click
on "I love it" or "Not so great" and cast their vote as shown below:
Any subsequent
mouse hover shows aggregated
results from other viewers as shown below:
The results are not interesting if there is a single viewer of the
movie. But for a production environment, this movie will be played by
multiple users concurrently and the percentage numbers will be more
meaningful. You can close the window and run the project again to vote
again, as many times as you like :)
For those who like to see quick results, here is a 4-step guide to get
started:
- In NetBeans 6.5 IDE, install JavaFX plugin as explained here and RESTful
Web services plugin as explained here. Both the
plugins may be installed in one step by selecting the required plugins
together.
- Download NetBeans project for JavaFX client from here
and add Jersey dependencies as explained in bullet #5
below.
- Download Web service endpoint Maven project from here
and deploy the endpoint as explained in bullet
#4 below.
- Run the JavaFX application as explained here.
The remainder of this blog explains the details and shows how to
construct the demo from scratch.
Lets first create the JavaFX application that plays the video movie.
- In NetBeans
6.5, install "JavaFX SDK" plugin. In
the "Tools"
menu, "Plugins", search on "JavaFX", select "JavaFX SDK" and click on
"Install".
- Create a new project of type "JavaFX", "JavaFX Script
Application". Take the default values as shown below:

and click on "Finish".
- The source code for this class can be downloaded from here
or alternatively constructed as explained in the sub-bullets.
- In the newly created class, change the Stage (root area
for
all scene content) to:
Stage {
title: "GlassFish Media Player"
width: 625
height: 360
resizable: false
scene:
myScene
} |
- Create a scene that contains the view of the media to be
played and controls the display of the Vote or Result nodes:
var myScene: Scene = Scene {
content: MediaView {
fitWidth: 625
fitHeight: 360
mediaPlayer:
bind myPlayer
onMouseEntered: function( e: MouseEvent ):Void {
println("mouse entered");
if (voted == false) {
insert Vote{} into
myScene.content;
} else {
insert
Result{}
into myScene.content;
}
}
onMouseExited: function( e: MouseEvent ):Void {
delete myScene.content[1]
}
}
} |
- Create a Media Player to use with the scene:
var myPlayer: MediaPlayer = MediaPlayer{
autoPlay: true
media:
bind myMedia
}; |
- Create the media object to be used with the Media Player:
var myMedia: Media = Media {
source:
"http://sun.edgeboss.net/download/sun/media/1460825906/1460825906_2957290001_DayEarth-Bluray.flv"
}; |
You can change the location of the movie here in the media player. For
example, changing it to
"http://mediacast.sun.com/users/ArunGupta/media/v3prelude-nb65-webapp.flv"
will start playing the screencast
#27.
- Create a Vote class that is a CustomNode and appears when
a
user's mouse enters the scene where the video is playing. The user can
select whether he likes the clip or not and the vote is recorded
making a Web service call using Jersey
Client APIs:
class Vote extends CustomNode {
override function create():Node {
return
Group {
content: [
Rectangle {
fill: Color.GREEN
x: 185
y: 145
width: 243
height: 38
arcWidth: 20
arcHeight: 20
},
Text {
x: 195
y: 170
fill: Color.WHITE
font: Font {
size: 18
}
content: "I love it"
},
Rectangle{
x: 191
y: 148
smooth: false
width: 73
height: 32
fill: Color.TRANSPARENT
onMouseClicked: function( e: MouseEvent ):Void {
println("clicked I love it");
voted = true;
wsClient.voteLoveIt();
delete myScene.content[1]
}
},
Text{
x: 305
y: 170
fill: Color.WHITE
font: Font {
size: 18
}
content: "Not so great"
},
Rectangle {
x: 301
y: 148
smooth: false
width: 118
height: 32
fill: Color.TRANSPARENT
onMouseClicked: function( e: MouseEvent ):Void {
voted = true;
println("clicked Not so great");
wsClient.voteNotSoGreat();
delete myScene.content[1]
}
}
]
}
}
}; |
- Create a Result class that is a CustomNode and simply
reports on how many voters like this clip:
class Result extends CustomNode {
override function create():Node {
var resultPercent =
wsClient.showResults();
var resultString =
"{resultPercent} voters liked this clip";
return
Group {
content: [
Rectangle {
fill: Color.BLUE
x: 187
y: 145
width: 244
height: 38
arcWidth: 20
arcHeight: 20
onMouseClicked: function( e: MouseEvent ):Void {
delete myScene.content[1]
}
},
Text {
x: 199
y: 170
fill: Color.WHITE
font: Font {
size: 18
}
content:
resultString
}
]
}
}
}; |
- Add two instance variables:
var voted = false;
var wsClient = new WebserviceClient; |
The first variable captures if the viewer has already voted and the
second variable is an instance to the RESTful Web service client.
- Add the following import statements:
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage; |
"Fix Imports" should be able to fix them and bug
#154307 is already filed for that.
- Create a new class that is used to capture the Vote as:
@javax.xml.bind.annotation.XmlRootElement
public class VoteBean {
public static enum VOTE { LOVE_IT,
NOT_SO_GREAT };
public VOTE vote;
public VoteBean() { vote = VOTE.LOVE_IT;
}
public VoteBean(VOTE vote) {
this.vote = vote;
}
} |
This is a simple Javabean with a standard JAXB annotation.
This ensures that XML is used as the data format for transfering
results between client and endpoint. The source code for this class is
available here.
- Add
Jersey libraries to the project by right-clicking on
Project, select Libraries, click on "Add Library...", select "JAX-RS
1.0" and "Jersey 1.0 (JAX-RS RI)", and click on "Add Library".

If these libraries
are not available then install the "RESTful Web
Services" plugin from the Plugin Center.
- And finally add the class that invokes the RESTful
Webservice
endpoint:
public
class WebserviceClient {
private static com.sun.jersey.api.client.WebResource
createWebResource() {
return com.sun.jersey.api.client.Client.create().
resource("http://localhost:8080/movie-feedback-webapp/webresources/myresource");
}
public static void voteLoveIt() {
createWebResource().type("application/json").
post(new
VoteBean(VoteBean.VOTE.LOVE_IT));
}
public static void voteNotSoGreat() {
createWebResource().type("application/json").
post(new
VoteBean(VoteBean.VOTE.NOT_SO_GREAT));
}
public static String showResults() {
return createWebResource().get(String.class);
}
} |
The Webservice endpoint will be hosted at
"http://localhost:8080/movie-feedback-webapp/webresources/myresource".
A WebResource is created from the Client. The POST methods are used to
cast the user vote and GET method is used to retrieve the aggregated
results. The source code for this class is available here.
Now lets create the RESTful endpoint using Jersey and deploy on
GlassFish.
- Create and deploy a RESTful Web service endpoint
- Create a template RESTful Web service endpoint as
described in TOTD
#56. Lets use the artifactId as "movie-feedback-webapp".
- Create the bean "VoteBean" in "org.glassfish.samples"
package. This is the exactly same bean used earlier by the client:
@javax.xml.bind.annotation.XmlRootElement
public class VoteBean {
public static enum VOTE { LOVE_IT,
NOT_SO_GREAT };
public VOTE vote;
public VoteBean() { vote = VOTE.LOVE_IT;
}
public VoteBean(VOTE vote) {
this.vote = vote;
}
}
|
- Update the generated resource
- Add @com.sun.jersey.spi.resource.Singleton
as class annotation so that only one instance of the resource is
created for the entire web
application. This allows to save state (preferences from other users)
in the RESTful resource.
- Add two instance variables:
int loveIt;
int noSoGreat; |
- Add a method that will process HTTP POST requests as:
@POST
public void postOneVote(VoteBean bean) {
if (bean.vote == VoteBean.VOTE.LOVE_IT) {
loveIt++;
} else {
noSoGreat++;
}
System.out.println("In POST: " + bean.vote);
} |
This method stores the vote in the resource. The handling of POST
request messages by Jersey is explained in TOTD
#58.
- Add a method that will process HTTP GET requests as:
@GET
@Produces("text/plain")
public String getOpinion() {
if (loveIt == 0 && noSoGreat == 0)
return "No votes cast yet!";
return (loveIt * 100) / (loveIt + noSoGreat) + "%";
} |
This method calculates the percentage of viewers who liked the movie.
- Deploy the
endpoint using "mvn glassfish:run" in
"movie-feedback-webapp" directory.
Now run the JavaFX application by
right-clicking on the project and
selecting "Run Project" and start voting! The percentage
results will vary if the movie is voted upon more than once.
This blog showed:
- How to install JavaFX capabilities to an existing NetBeans
6.5 installation
- How to create a simple JavaFX application that plays media
files
- Integrate it with existing Java libraries (Jersey client
libraries in this case)
- Invoke services hosted on GlassFish
The steps followed in this blog allows for rapid development/debugging
of JavaFX application accessing resources using embeddable GlassFish
but are not ideal for production deployments. A future
blog will show how this JavaFX application can be deployed as a
Java
Web Start application and scaled for mulitple users.
The
javafx.com/samples
has loads of samples and
javafx.com/tutorials
shows how to build your own applications. The
JavaFX
Community Wiki is a great place to collaborate.
Send your Jersey questions to
users@jersey.dev.java.net,
GlassFish questions to
GlassFish
Forum, and JavaFX questions to
JavaFX
Forums.
Technorati:
glassfish
v3
jersey
webservices
javafx