In this post, I am going to show you how to use JavaFX Application client to access stateless EJB in order to persist data to database. You can access the posts where I created a Postgres Database, Datasource for Wildfly Application Server, EJB Module Project which contains the stateless Session Bean and the Entity Bean Class. Please refer to the Links provided.

EJB 3.0, entity bean used in EJB 2.0 is largely replaced by persistence mechanism. Now
entity bean is a simple POJO having mapping with table. The key factors in Java persistence API are:

  • Entity – A persistent object representing the data-store record. It is good to be
    serializable.
  • EntityManager – Persistence interface to do data operations like
    add/delete/update/find on persistent object (entity). It also helps to execute
    queries using Query interface.
  • Persistence unit (persistence.xml) – Persistence unit describes the properties
    of persistence mechanism.
  • Data Source (*ds.xml) – Data Source describes the data-store related properties
    like connection url. user-name, password, etc.

We need to do the following tasks to accomplish this tutorial:

  • Create table in database. Refer to this Link
  • Create Entity class corresponding to table. Refer to this Link
  • Create Data Source and Persistence Unit. Refer to this Link
  • Create a stateless EJB having EntityManager instance. Refer to this Link
  • Update stateless EJB. Add methods to add records and get records from database via entity manager. Refer to this Link
  • Create/Design JavaFX application client will access the stateless EJB to persist data in database.
  1. To create/design a JavaFX GUI, you either use the Screen Builder or do it programmatically which is more fun. For the purpose of this tutorial, we shall be using a screen Builder. Proceed to Netbeans, from the new project wizard, go down to JavaFX, and choose JavaFX application. Click next.
  2. In the next window, input the project name (Car Rental Client), project location and folder, JavaFX platform (JDK 1.8. Might be different in yours, depending on the version of your JDK), you can choose to tick Create Application Class. If you leave it ticked, modify the package name and Class name to suit your taste but make sure it adheres to the rules of java class names. Click on finish.
  3. Right-click again on the package node, go to new, choose Empty FXML. Supply the FXML name (addCarFXML), other inputs should be automatically setup. Click on next.
  4. In the next window, check Use Java Controller box, supply the Controller name (AddCarFXMLController) or if you have an already controller class to use, check Use Existing box, then supply the location but for now, just click next.
  5. In the next window, you can create a CSS file for the GUI or use an existing one but for now, leave all unchecked. We will add CSS later. Click on finish and the FXML file with its controller will be created.
  6. Double click on the FXML (addCarFXML) file to open it from the Screen Builder. Use the screen builder to design the Interface. Most Importantly, add three Buttons (Connect, Browse, Add Car), set their onAction methods. Finally, save.
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.collections.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="600.0" stylesheets="@../../css/rentalcss.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.add.AddCarFXMLController">
   <children>
      
                  <Label layoutX="39.0" layoutY="80.0" text="Car Name" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="112.0" text="Car Model" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="142.0" text="Year" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="175.0" text="Image" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="213.0" text="Catergory" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="248.0" text="Available" AnchorPane.leftAnchor="50.0" />
                  <TextField fx:id="nameField" layoutX="179.0" layoutY="76.0" prefHeight="25.0" prefWidth="220.0" />
                  <TextField fx:id="modelField" layoutX="179.0" layoutY="108.0" prefHeight="25.0" prefWidth="220.0" />
                  <TextField fx:id="yearField" layoutX="179.0" layoutY="138.0" prefHeight="25.0" prefWidth="220.0" />
                  <Label layoutX="39.0" layoutY="284.0" text="Rental Price/day (N)" AnchorPane.leftAnchor="50.0" />
                  <Label layoutX="39.0" layoutY="316.0" text="Manufacturer" AnchorPane.leftAnchor="50.0" />
                  <ComboBox fx:id="categoryBox" layoutX="180.0" layoutY="209.0" prefHeight="25.0" prefWidth="218.0" promptText="Choose Car Category">
                      <items>
                          <FXCollections fx:factory="observableArrayList">
                              <String fx:value="VIP" />
                              <String fx:value="IP" />
                              <String fx:value="CLASS" />
                              <String fx:value="NORMAL" />
                          </FXCollections>
                      </items>
                 
                  </ComboBox>
                  <TextField fx:id="imageField" layoutX="180.0" layoutY="171.0" prefHeight="25.0" prefWidth="219.0" />
                  <TextField fx:id="priceField" layoutX="180.0" layoutY="280.0" prefHeight="25.0" prefWidth="216.0" />
                  <ComboBox fx:id="manufactuerField" editable="true" layoutX="180.0" layoutY="312.0" prefHeight="25.0" prefWidth="215.0" promptText="Choose Car Manufacturer">
                     <items>
                          <FXCollections fx:factory="observableArrayList">
                              <String fx:value="Toyota" />
                              <String fx:value="Mercedes" />
                              <String fx:value="BMW" />
                              <String fx:value="Ferari" />
                              <String fx:value="Volkswagen" />
                              <String fx:value="Mazda" />
                              <String fx:value="Mitshubi" />
                          </FXCollections>
                      </items>
                  </ComboBox>

                  <CheckBox fx:id="yesCheck" layoutX="179.0" layoutY="248.0" mnemonicParsing="false" text="YES" />
                  <CheckBox fx:id="noCheck" layoutX="348.0" layoutY="248.0" mnemonicParsing="false" text="NO" />
                  <Button fx:id="browseBtn" layoutX="445.0" layoutY="171.0" mnemonicParsing="false" onAction="#browseBtnAct" text="Browse" />
                  <Button fx:id="addCarBtn" layoutX="248.0" layoutY="373.0" mnemonicParsing="false" onAction="#addCarBtnAct" text="ADD CAR" />
      <Label fx:id="statusLabel" alignment="CENTER" layoutX="182.0" layoutY="428.0" prefHeight="17.0" prefWidth="227.0" text="Not Connected.." />
      <Button fx:id="connectBtn" layoutX="236.0" layoutY="37.0" mnemonicParsing="false" onAction="#connectBtnAct" prefHeight="25.0" prefWidth="95.0" text="Connect" />
      
               
      
      
   </children>
</AnchorPane>

 

  1. From Netbeans, right-click on addCarFXML and choose Make Controller. The contents from the FXML will be injected into the Controller Class (AddCarFXMLController).
  2. The AddCarFXMLController extends Service Class from javafx.concurrent package and also implements Initializable interface with its abstracts method initialize. FXMLLoader will automatically call any suitably annotated no-arg initialize() method defined by the controller and load resources from the FXML file denoted by @FXML annotation.
package com.add;

import com.rental.entity.Info;
import com.rental.remoteinterace.rentalRemote;
import com.update.UpdateModel;
import java.io.File;
import java.net.URL;
import java.net.ConnectException;
import java.util.Properties;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.FileChooser;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
 * FXML Controller class
 *
 * @author STEINACOZ-PC
 */
public class AddCarFXMLController extends Service<Void> implements Initializable {

    @FXML
    private TextField nameField;
    @FXML
    private TextField modelField;
    @FXML
    private TextField yearField;
    @FXML
    private ComboBox<?> categoryBox;
    @FXML
    private TextField imageField;
    @FXML
    private TextField priceField;
    @FXML
    private ComboBox<?> manufactuerField;
    @FXML
    private CheckBox yesCheck;
    @FXML
    private CheckBox noCheck;
    @FXML
    private Button browseBtn;
    @FXML
    private Button addCarBtn;
    
    private  String filename;
    private String filePath;
    Properties props;
    InitialContext ctx = null;
    rentalRemote rentalBean;
    @FXML
    private Label statusLabel;
    @FXML
    private Button connectBtn;
    

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
//changes to statuslabel text to red when not connected
    statusLabel.setText("Not Connected");
    statusLabel.setStyle("-fx-text-fill: red;");
    browseBtn.setVisible(false);
    addCarBtn.setVisible(false);
       
       
    }    

    @FXML
    private void browseBtnAct(ActionEvent event) {
        File f = null;
        FileChooser fc = new FileChooser();
        fc.setTitle("Choose Car Image");
        
        f = fc.showOpenDialog(null);
        filename = f.getName();
        filePath = f.getAbsolutePath();
        this.imageField.setText(filename);
        setFile(filePath);
    }
    
   

    @FXML
    private void addCarBtnAct(ActionEvent event) {
   if(this.nameField.getText().isEmpty() || this.imageField.getText().isEmpty() || this.modelField.getText().isEmpty() || this.priceField.getText().isEmpty() || this.yearField.getText().isEmpty()){
       statusLabel.setText("Operation Failed...empty parameters");
       statusLabel.setStyle("-fx-text-fill: FF0000");
       System.out.println(nameField.getText());
   }else{
       
       String avail = null;
       
       //handles availablity check buttons
       if(yesCheck.isSelected()){
           noCheck.setSelected(false);
           avail = "YES";
       }else if(this.noCheck.isSelected()){
           yesCheck.setSelected(false);
           avail = "NO";
       }
       
       //handles combobox
        String category = this.categoryBox.getValue().toString();
        System.out.println(category);
        String manu = this.manufactuerField.getValue().toString();
       
       rentalBean.addNewCar(nameField.getText(), modelField.getText(), avail, category, getFilepath(), manu, priceField.getText(), yearField.getText());
       statusLabel.setStyle("-fx-text-fill: 0ce413");
       statusLabel.setText(rentalBean.getStatusMsg());
       
       if (statusLabel.getText().equalsIgnoreCase("Operation successful")){
           this.nameField.setText("");
           this.modelField.setText("");
           this.imageField.setText("");
           this.yearField.setText("");
           this.priceField.setText("");
           this.yesCheck.setSelected(false);
           this.noCheck.setSelected(false);
           
       }
      
   }
    }
    
     String getFilepath(){
        return filePath;
    }
    
    private void setFile(String name){
      filePath = name;
    }

    @FXML
    private void connectBtnAct(ActionEvent event) {
        if (connectBtn.getText().equals("Connect")){
        ready();
        connectBtn.setText("Connecting..");
        connectBtn.setDisable(true);
        connectBtn.setStyle("-fx-text-fill: red;");
        start();  
        }
    }
    
      public void restartCon(){
          
        connectBtn.setText("Connecting");
        connectBtn.setStyle("-fx-text-fill: red;");
        cancel();
        restart();
           
                   
        }
     @Override
    protected Task<Void> createTask() {
       return new Task<Void>(){
               @Override
               protected Void call() throws Exception {
                   
               
                try{
                        
                props = new Properties();
                props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
                props.put(Context.PROVIDER_URL, "http-remoting://localhost:8050");
                props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                props.put(Context.SECURITY_PRINCIPAL, "steinacoz");
                props.put(Context.SECURITY_CREDENTIALS, "nkenna007");
                props.put("jboss.naming.client.ejb.context", true);
                
                ctx = new InitialContext(props);
                
                
                rentalBean = (rentalRemote) ctx.lookup("CarRental-ejb/rentalBean!com.rental.remoteinterace.rentalRemote");
                 
            Platform.runLater(new Runnable(){
           @Override
           public void run() {
              statusLabel.setText("Connected");
              statusLabel.setStyle("-fx-text-fill: green;");
              connectBtn.setText("Connected");
              connectBtn.setDisable(false);
              statusLabel.setStyle("-fx-text-fill: green;");
              browseBtn.setVisible(true);
              addCarBtn.setVisible(true);
           }
         
     });
               }catch(NamingException ex){
                

                Platform.runLater(new Runnable(){
           @Override
           public void run() {
             statusLabel.setText("Error in Connection, Try Again");
             statusLabel.setStyle("-fx-text-fill: red;");
             connectBtn.setText("Connect");
             connectBtn.setDisable(false);
             statusLabel.setStyle("-fx-text-fill: red");
             restartCon();
             browseBtn.setVisible(false);
             addCarBtn.setVisible(false);
              
           }
         
     });
                      
            }
                          
                    return null;
                    
               }
               
           };
                
        }
    
}

 

  1. Inside the initialize method, browse button and add car button is set to invisible to prompt the user to use the connect button. The statusLabel text is set to “not connected” and text color to red to indicate that Connection to the Server have not been made.
  2. The browse button onAction() method invokes a fileChooser dialog to get the image name and image file path.
  3. The add car button onAction() method calls the addNewCar() method of the Session bean class passing the relevant parameters to it.
  4. The connect button onAction() method calls the start() method of Service Class to create a new task for connecting to the server. Since JavaFX UI(s) can’t be updated directly from another thread apart from the JavaFX application thread, platform.runlater class will be called to update the buttons and labels after the connection have been made.
 Platform.runLater(new Runnable(){
           @Override
           public void run() {
             statusLabel.setText("Error in Connection, Try Again");
             statusLabel.setStyle("-fx-text-fill: red;");
             connectBtn.setText("Connect");
             connectBtn.setDisable(false);
             statusLabel.setStyle("-fx-text-fill: red");
             restartCon();
             browseBtn.setVisible(false);
             addCarBtn.setVisible(false);
              
           }
         
     });

 

  1. The Application will try to reconnect automatically if the connection fails from restartCon() method.

add3

add1

 

add2

 

Refer to this Post on how to skin the UI with CSS.

LEAVE A REPLY

Please enter your comment!
Please enter your name here