JavaFX and Seam with Flamingo: Part Two
Join the DZone community and get the full member experience.
Join For FreeThis is a second part of the JavaFX and Seam with Flamingo article series. Building on the background information from the first part of the article, this second part provides a step-by-step tutorial for building a JavaFX applications that talks to a Seam backend.
What We Are Going to Build
Here is a screen shot of the application we are going to build. The application allows adding and deleting users.
What You Need
You will need the following software to get through the example. You may have some of the tools already:
JavaFX SDK
Eclipse 3.4.2
Exadel JavaFX Studio plug-in for Eclipse
JBoss Application Server 4.3.2 (to deploy Seam application)
Ready-to-deploy Seam application
Exadel Flamingo
Note: If you would just rather read the tutorial without doing the steps, I have provided a finished application at the end that you can download and deploy to JBoss AS. See the “Finished Application” section.
JavaFX SDK
Download the JavaFX SDK for your operating system
Install JavaFX SDK
Eclipse 3.4
If you don't have Eclipse 3.4.2, please download it from here. While plain Eclipse is sufficient, it would be a good idea to download the Eclipse IDE for Java EE Developers package. All you need to do is unzip the downloaded file.
Exadel JavaFX Studio plug-in for Eclipse
The Exadel JavaFX Studio plug-in for Eclipse provides features to help build and deploy JavaFX applications. The plug-in is free. Go to the JavaFX Studio page and click the Download link on the left-side menu.
You are not required to use this plug-in. It's quite possible to build this application just using the JavaFX SDK and command line tools; however, the plug-in will greatly simplify this process.
Plug-in Installation
Download the plugin, unzip the downloaded file
Start the Eclipse IDE
On the Help menu select Software Updates
In the Software Updates and Add-ons dialog click on the Available Software tab
Click on the Add Site button, choose Local, navigate to the folder with the unzipped plug-in, select that directory (where the unzipped plug-in resides), and press OK
You will see the "Exadel JavaFX 1.0 Update Site" option in the list. Check the option and press Install. Follow the Installation procedure to install the plug-in. In the end you will be asked to restart the IDE.
Configure JavaFX SDK
Select Window/Preferences/JavaFX
Click Add...
Browse to the folder where you installed the JavaFX SDK
Click Finish. You have now configured the JavaFX SDK.
One final step is to test the plug-in (we will re-use this project later):
Select File/New/Other.../
Select JavaFX/JavaFX Project
Click Next
For Project name enter: javafx-seam
Click Finish
Expand the project, right-click src, and then select New/Package
For a package name enter: test
Click Finish
Right-click test package and select New/Other.../JavaFX/JavaFX Script
Click Next
For File name enter: test (you don't need to enter .fx)
Click Next
Check Generate Stage. A file will be created with a simple JavaFX stage.
Right-click anywhere in the source and select Run As/JavaFX Application. A window should open with a “Hello World” message. If you see this window, then everything is working.
JBoss AS
If you don't have JBoss AS 4.2.3, please download it. All you need to do is unzip the downloaded file. This application was tested with JBoss AS 4.2.3 GA.
Seam application
Download the Seam application.
The application is finished and ready to be deployed. Copy the file to <jbossas>/server/default/deploy
To start the server, run <jboss>/bin/run
To make sure the application deploys OK, go to [http://localhost:8080/flamingods and click on the link on the page. . This is a JSF page to display users in a table. If you see this page, then the application was deployed successfully
Let's review the Seam application code.
There is a User class that looks like this:
public class User {
@Length(min=3, max=40)
private String name;
public User (){
}
public User(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}
User is basically our model in this application.There is also a userManager component that looks like this:
@Scope (ScopeType.SESSION)
@Name ("userManager")
public class UserManager {
@In (required=false)
@Out (scope=ScopeType.SESSION, required=true)
private List <User> userList;
@Logger
private Log log;
@Factory ("userList")
public void create () {
userList = new ArrayList <User> ();
User user1 = new User ("John");
User user2 = new User ("Charley");
User user3 = new User ("Sergey");
userList.add(user1);
userList.add(user2);
userList.add(user3);
}
public void remove (int index){
User userToDelete = userList.get(index);
log.info("Deleting user: "+userToDelete.getName());
userList.remove(userToDelete);
log.info("all users: "+userList);
}
public void addUser (String name){
User user = new User ();
user.setName(name);
userList.add(user);
log.info("addUser(String) Added new user: "+user.getName());
log.info("all users: "+userList);
}
}
The userManager component holds the list of users and knows how to add and delete users.
Flamingo
And finally we need to download Flamingo
Download Flamingo
Unzip the file (We will come back to Flamingo a little bit later.)
JavaFX Talking to Seam
Now that we have the server part (Seam) working, we are going to create a JavaFX user interface and connect it to the server-side. These are the general steps:
Create JavaFX user interface
Create client-side service interfaces
Create a client-side factory
Modifying JavaFX script
Setting server URL
Loading existing users
Adding a user
Deleting a user
Validation
Creating a JavaFX user interface
You have already created a project (javafx-seam), so let's re-use it.
Create a new Java class: example.model.User (notice the package name)
Copy and paste the following:
package example.model;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name) {
super();
this.name = name;
}
public User (){}
@Override
public String toString() {
return this.name;
}
}This is a straightforward Java bean and will be used as a model object.
Create a new package: example.javafx
Right click the created package and select New/Other.../JavaFX/JavaFX Script
- For a name enter: UsersView
- Click Finish
- Copy and paste the following
JavaFX Script.
package example.javafx;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.layout.Tile;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.control.TextBox;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import example.model.User;
var users: User[];
function add () : Void {
var newUser:User = new User ();
newUser.setName (inputText.text);
insert {newUser} into users;
}
function remove (idx : Integer) : Void {
delete users[idx];
}
var inputText : TextBox = TextBox {
columns: 20
}
var buttonAdd : Button = Button {
text: "Add"
style: "base: blue"
action: function () {add()}
}
var buttonClear : Button = Button {
text: "Clear"
style: "base: blue"
action: function () {inputText.text = "";}
}
Stage {
title: 'JavaFX and Seam'
scene: Scene {
width: 500
height: 300
content: [
VBox {
translateX: 5
translateY: 5
content: [
VBox {
spacing: 8
content: [
HBox {
content: [inputText]
}
HBox {
spacing: 8
content: [buttonAdd, buttonClear]
}
]
},
VBox {
translateX: 10
translateY: 20
spacing: 5
content: bind for (p in users) {
HBox {
spacing: 8
content:[
Text {
font: Font { size: 16 }
content: (p.getName() )
}
Button {
height: 16
style: "base: blue"
text: 'Delete'
action:function () {remove(indexof p)}}
]
}
}
}
]
}
]
}
}
What you see here is rather basic JavaFX script. It's not yet connected to anything, but we can already run it.Right-click in the editor and select Run/JavaFX Application. You should see the following:
You can also run this as an applet, by selecting Run/JavaFX Application (Applet). You should see the following:
Note: once we add communication with server, you will get errors when running as applet. We will fix that by signing the jar files. Just giving you a heads up if you run as applet again.
From now on, we will edit this JavaFX script file.
Creating client-side service interfaces
Before we can call Seam component methods from JavaFX, we need to know which methods are actually available in the Seam component. This is done by creating a service interface that looks like this:
package example.service;
public interface UserManager {
public void remove (int index);
public void addUser (String name);
}
f you look at the Seam code, there is a userManager component with the same methods.There is also one more for a Binding service
package example.service;
public interface BindingManager {
public Object getObject(String componentName);
}
BindingManager is a Flamingo-built in server-side component so you don't need to create it.
Creating a client-side service factory
At this point we have to add the Flamingo and Hessian .jar files. (Hessian is the binary protocol that is used in Flamingo to communicate with the server.)
Create a lib directory in the javafx-seam project. You can use Eclipse to create the directory
Copy the <flamingo>/bin/flamingo-javafx-1.8.1.jar to the javafx-seam/lib directory
Download the Hessian jar, http://hessian.caucho.com/download/hessian-3.1.5.jar and copy it to javafx-seam/lib as well.
Expand the lib folder and select both files. Right-click and select Build Path/Add to Build Path
Next we need to create a client-side reference (or proxy) to Seam components:
package example.service;
import java.util.List;
import com.exadel.flamingo.javafx.ServiceFactory;
import example.model.User;
public class AppServiceFactory {
public static BindingManager getBindingManager() {
return (BindingManager) ServiceFactory.getService(BindingManager.class,
"com.exadel.flamingo.service.binding.bindingManager");
}
public static UserManager getUserManager() {
return (UserManager) ServiceFactory.getService(UserManager.class, "userManager");
}
public static User[] getUserList() {
List<User> list = (List<User>) getBindingManager().getObject("userList");
User[] temp = new User[list.size()];
User[] users = list.toArray(temp);
return users;
}
}
The getService in Flamingo takes two arguments: (1) service interface and (2) Seam component name. com.exadel.flamingo.service.bindingManager is a built-in Flamingo component that binds a Seam variable in some context. userManager is a Seam component defined by us (see the server-side code).
The last method, getUserList(), uses BindingManager to bind to the Seam userList variable. That's all we need to start calling Seam components.
Modifying the JavaFX script
Setting the server URL
Before we can make any calls to Seam components, we need to tell JavaFX where the components are by setting the server URL. Open UsersView.fx and add the following:
import com.exadel.flamingo.javafx.ServiceFactory;
...
ServiceFactory.setUrl('http://localhost:8080/flamingo-ds/seam/resource/hessian/');
s etUrl(..) can go anywhere before the add(..) function.
When running as a stand-alone JavaFX application, you also need to add the following (changes are in bold) in order to support cookies (to have session support on the server):
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
...
ServiceFactory.setUrl('http://localhost:8080/flamingo-ds/seam/resource/hessian/');
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
Note: When you run as an applet, the Java plug-in has this support by default so you don't have to do anything.
Once you add this, you will start getting compile errors. This is because JavaFX SDK ships with a trimmed down version of rt.jar file (called rt15.jar). We are going to use rt.jar from your JVM. These are the steps:
Rename <javafxsdk>/lib/desktop/rt15.jar to rt15_original.jar
Copy <jvm>/lib/rt.jar to <javafxsdk>/lib/desktop/
Rename the just copied file to rt15.jar
Loading existing users
Inside the Seam component, there are three existing users. When we launch the JavaFX application, we would like to display the users. In order to do that, we are going to bind to the userList variable.
Inside AppServiceFactory, there is a list of Users that needs to be inserted into an array on the JavaFX side. We need to create a sequence (similar to an array) to hold the users.. That's one of the beauties of JavaFX, it naturally integrates with Java.
Replace this line:
var users: User[] ;
with this:
import com.exadel.flamingo.javafx.FlamingoServiceFactory;
import example.service.*;
...
var users: User[] = AppServiceFactory.getUserList ();
Save all changes
Start JBoss AS server, <jbossas>/bin/run
Right-click in the JavaFX script editor and select Run/JavaFX Application. You should get this:
Adding a user
To add a user on the server, we need to make a call to a Seam component :
function add () : Void {
var newUser:User = new User ();
AppServiceFactory.getUserManager().add(inputText.text);
newUser.setName (inputText.text);
insert {newUser} into users;
}
You can also look in JBoss AS console to see that a user was inserted on the server.
Deleting a user
Deleting a user is equally simple
function remove (idx : Integer) : Void {
AppServiceFactory.getUserManager().remove(idx);
delete users[idx];
}
Run the application and try deleting Charley. You should get this:
Validation
One last thing we are going to do is add validation. Right now you can click the Add button without entering anything. Let's fix that.
Add a variable to hold the actual error message returned from the server:
var message : String;
Then, we need to create a new Text node that will display the error message:
var messageText : Text = Text{
font: Font { size: 16 }
content: bind message
}
Adding the new node to scene graph
HBox {
content: [inputText , messageText]
}
Now we need to validate against Hibernate Validator annotations defined in the user component in Seam. At the beginning of the add() function, add this:
message = FlamingoServiceFactory.getHessianEntityValidator().validate("user.name", inputText.text);
if ( message != null ){
return;
}
FlamingoServiceFactory is a built-in factory (just like our AppServiceFactory). It creates an entity validator component that validates against Hibernate Validator annotations. user is a Seam component name, and name is a property. inputText.text is a JavaFX script node where we enter the name.
Save and run the application. If you don't enter anything in the input field or input less than 3 characters, you will get this:
Launching as an applet
Before we can launch as an applet, we have to sign the jar files.
Go to <workspace>/<javafx-users/build
Enter the following command:
keytool -genkey -dname "cn=JavaFX Example, ou=Flamingo Project, o=Exadel, c=US" -keypass changeit -storepass changeit -keystore ./keystore.dat -keyalg rsa -alias flamingokey
this step generates a key called keystore.dat in current directoryNext, we are going to sign the three jar files needed on the client-side. Each time you will be prompted for a password which is: change it (see step 2)
jarsigner -keystore ./keystore.dat build/UsersView.jar flamingokey
jarsigner -keystore ./keystore.dat build/lib/hessian-3.1.5.jar flamingokey
jarsigner -keystore ./keystore.dat build/lib/flamingo-javafx-1.8.1.jar flamingokey
Right-click in the JavaFX Script editor and select JavaFX Application (Applet).
You will see a message asking if you trust the publisher. Click Run.
Web browser will be launched and you should see the following:
Finished Application
If you want to just run the finished application, follow the steps below:
Download the finished application
Copy it to <jbossas>/server/defualt/deploy.
Run <jbossas>/bin/run
In browser, enter http://localhost:8080/flamingods-finished/
Select Users (JavaFX) link
You will see a dialog asking if you trust the publisher. Click Run.
Note: This setup is slightly different than the steps in this tutorial. The tutorial developed and deployed the JavaFX application separately. The finished application is packaged as a complete web application.
Final Words
It might seem like there have been a lot of moving parts in this article. In reality, connecting JavaFX to a Seam backend is very transparent and straightforward. The goal of the 2nd part was to show you (in a a hands-on way) how the various parts fit together to create seamless integration, so we didn’t take any shortcuts. However, remember, the first part of the article mentioned a CRUD-like framework. Using this, you can generate most of the parts. Future articles will cover how to use that.
Looking down the road, both Flamingo and Exadel JavaFX Studio plug-in for Eclipse have lots of new features planned. One of them is, of course, Flamingo and plug-in integration. Also, tasks such as signing JARs and deployment will be automated even further.
Finally, if you have any feedback, please post it on the [Flamingo forum, http://exadel.com/web/portal/flamingo/forum] or the [JavaFX Studio forum, http://groups.google.com/group/exadel-javafx-plug-in-for-eclipse].
Resources
Exadel Flamingo - http://exadel.com/web/portal/flamingo
Exadel JavaFX plug-in for Eclipse - http://exadel.com/web/portal/javafxstudio
Authors blog – http://mkblog.exadel.com
Opinions expressed by DZone contributors are their own.
Comments