Wednesday, June 15, 2011

JavaFX 2.0 Sample Application

After waiting a long time for it , finally javafx 2.0 beta was released.

I downloaded netbeans IDE 7 and Javafx FX 2.0 plugin. After playing with several javafx sample projects everthing seemed fine and I decided to develop a new application based on my sample finance project available at http://code.google.com/p/seahorse-ria-framework/downloads/list.

You can also download javafx 2.0 based sample client application from http://code.google.com/p/seahorse-ria-framework/downloads/list.

Sample javaFX client application contains a login and customer search page. For the authentication and customer search operations JEE based server side application is called from JSE based javaFX application.


I already had sample server side business project uploaded to google code, so I needed only to develop javaFX based rich client application that calls existing server based application.

Developing a sample application took several hours, most of job was coping codes from javafx samples projects into my sample project. A few thing did not  worked as I expected.(promp text ) .

Generally everthing was fine and it was very simple to develop an application with Javafx 2.0. 

Following diagram shows software architecture of sample application;








Following code segment shows login page;

 package com.seahorse.test.javafx;


import com.seahorse.bean.config.property.PropertyHelper;

import com.seahorse.bean.constant.SeaHorseConstants;

import com.seahorse.bean.container.BeanHelper;

import com.seahorse.common.util.ExceptionUtil;

import com.seahorse.support.web.SeaHorseStandaloneInitializer;

import com.seahorse.test.service.LoginService;

import javafx.application.Application;

import javafx.event.ActionEvent;

import javafx.event.EventHandler;

import javafx.geometry.Insets;

import javafx.scene.Scene;

import javafx.scene.control.*;

import javafx.scene.image.Image;

import javafx.scene.image.ImageView;

import javafx.scene.input.MouseEvent;

import javafx.scene.layout.GridPane;

import javafx.scene.layout.HBox;

import javafx.scene.layout.VBox;

import javafx.scene.paint.Color;

import javafx.scene.text.TextAlignment;

import javafx.stage.Stage;

public class Login extends Application {

final Label messageLabel = new Label("");

@Override

public void start(final Stage stage) {

Image image = new Image(getClass().getResourceAsStream("not.png"));

messageLabel.setGraphic(new ImageView(image));

messageLabel.setTextFill(Color.web("#0076a3"));

messageLabel.setTextAlignment(TextAlignment.JUSTIFY);

messageLabel.setWrapText(true);

messageLabel.setMaxWidth(300);

GridPane grid = new GridPane();

grid.setPadding(new Insets(0, 10, 10, 10));

grid.setVgap(5);

grid.setHgap(5);

Label userIdLabel = new Label("User Id");

GridPane.setConstraints(userIdLabel, 0, 0);

grid.getChildren().add(userIdLabel);

final TextBox userIdText = new TextBox();

userIdText.setText("1");

userIdText.setPromptText("Enter User id");

userIdText.setColumns(20);

GridPane.setConstraints(userIdText, 1, 0);

grid.getChildren().add(userIdText);

Label passwordLabel = new Label("Password");

GridPane.setConstraints(passwordLabel, 0, 1);

grid.getChildren().add(passwordLabel);


final PasswordBox passwordText = new PasswordBox();

passwordText.setText("seahorse");

passwordText.setPromptText("Enter password");

GridPane.setConstraints(passwordText, 1, 1);

grid.getChildren().add(passwordText);


final Button submit = new Button("Login");

submit.setOnMouseEntered(new EventHandler() {

@Override public void handle(MouseEvent e) {

submit.setScaleX(1.25);

submit.setScaleY(1.25);

}

});

submit.setOnMouseExited(new EventHandler() {

@Override public void handle(MouseEvent e) {

submit.setScaleX(1);

submit.setScaleY(1);

}

});

Button clear = new Button("Clear");

HBox hbButton = new HBox();

hbButton.setPadding(new Insets(5, 0, 0, 0));

hbButton.setSpacing(10);


hbButton.getChildren().addAll( submit,clear);


GridPane.setConstraints(hbButton, 1, 2);

grid.getChildren().add(hbButton);


submit.setOnAction(new EventHandler() {

@Override

public void handle(ActionEvent e) {


if (userIdText.getText() == null

userIdText.getText().isEmpty()

passwordText.getText() == null

passwordText.getText().isEmpty() ) {

messageLabel.setText("User Id and password can not be empty!");

return;

}

LoginService loginService = BeanHelper.getBean(LoginService.class);


boolean isAuthorized = false;

try {


isAuthorized = loginService.login(Integer.valueOf(userIdText.getText()).intValue() , passwordText.getText() );

} catch (Exception ex) {

messageLabel.setText(ExceptionUtil.handleException(ex).getMessage());

messageLabel.setTextFill(Color.rgb(210, 39, 30));

}


if (isAuthorized) {

CustomerSearch ll = new CustomerSearch();

ll.start(stage);

}

}

});


clear.setOnAction(new EventHandler() {

@Override

public void handle(ActionEvent e) {

userIdText.clear();

passwordText.clear();

messageLabel.setText("");

}

});



VBox vb = new VBox();

vb.setPadding(new Insets(10, 0, 0, 10));

vb.setSpacing(10);



vb.getChildren().addAll( messageLabel,grid);

final Scene scene = new Scene(vb, 300, 150);

stage.setScene(scene);

stage.setTitle("Login Page");


stage.setVisible(true);

}

public static void main(String[] args) {

SeaHorseStandaloneInitializer.initialize();

//weblogic (check port number)

PropertyHelper.getPropertyManager().setProperty(SeaHorseConstants.DEFAULT_REMOTE_SERVER_NAME, http://localhost:7001/remote/remote/);


Application.launch(args);

}

}



After running login , following login page is displayed






When login button is pressed,  login service on remote server will be called using the following code segment

LoginService loginService = BeanHelper.getBean(LoginService.class);


boolean isAuthorized = false;

try {

isAuthorized = loginService.login(Integer.valueOf(userIdText.getText()).intValue() , passwordText.getText() );

after successfull login, customer search page is called using the following code segment;


package com.seahorse.test.javafx;

import com.seahorse.bean.container.BeanHelper;
import com.seahorse.common.util.ExceptionUtil;
import com.seahorse.test.model.Customer;
import com.seahorse.test.service.CustomerService;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class CustomerSearch {

    final TextBox searchText = new TextBox();
    private TableView tableView;
    private ObservableList tableItems;

    public static class CustomerFX {

        private IntegerProperty customerId;

        public void setCustomerId(Integer value) {
            customerIdProperty().set(value);
        }

        public Integer getCustomerId() {
            return customerId.get();
        }

        public IntegerProperty customerIdProperty() {
            if (customerId == null) {
                customerId = new IntegerProperty();
            }
            return customerId;
        }
        private StringProperty name;

        public void setName(String value) {
            nameProperty().set(value);
        }

        public String getName() {
            return name.get();
        }

        public StringProperty nameProperty() {
            if (name == null) {
                name = new StringProperty();
            }
            return name;
        }
        private StringProperty surname;

        public void setSurname(String value) {
            surnameProperty().set(value);
        }

        public String getSurname() {
            return surname.get();
        }

        public StringProperty surnameProperty() {
            if (surname == null) {
                surname = new StringProperty();
            }
            return surname;
        }
    }

    public void start(Stage primaryStage) {

        primaryStage.setWidth(500);
        primaryStage.setHeight(400);
        primaryStage.setTitle("Customer Search Page");

        VBox vb = new VBox();
        vb.setPadding(new Insets(10, 10, 10, 10));
        vb.setSpacing(10);

        Scene scene = new Scene(vb, 500, 400, Color.BEIGE);

        //   searchText.setPromptText("Enter Customer id");  does not work!!
        searchText.setColumns(20);


        Label searchLabel = new Label("Search:");

        HBox searchBox = new HBox();
        searchBox.setSpacing(5);
        searchBox.setAlignment(Pos.CENTER_LEFT);

        searchBox.getChildren().addAll(searchLabel, searchText);


        final ChoiceBox cb = new ChoiceBox(FXCollections.observableArrayList(
                "Customer ID", "First Name", "Last Name"));

        cb.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener() {

            public void changed(ObservableValue ov, Number value, Number new_value) {

                if (new_value.intValue() == 0) {
                    searchText.clear();
                    //searchText.setPromptText("Enter Customer id");   // does not workkkk!!!
                } else if (new_value.intValue() == 1) {
                    searchText.clear();
                    //searchText.setPromptText("Enter First Name");
                } else {
                    searchText.clear();
                    //searchText.setPromptText("Enter Last Name");
                }
            }
        });

        Label criteriaLabel = new Label("Using:");

        HBox criteriaBox = new HBox();
        criteriaBox.setSpacing(5);
        criteriaBox.setAlignment(Pos.CENTER_LEFT);

        criteriaBox.getChildren().addAll(criteriaLabel, cb);

        Button searchButton = new Button();
        searchButton.setText("Search");

        Button btnClear = new Button();
        btnClear.setText("Clear");

        btnClear.setOnAction(new EventHandler() {

            public void handle(ActionEvent event) {
                tableItems.clear();
                cb.getSelectionModel().selectFirst();
            }
        });

        HBox hbButtonBox = new HBox();
        hbButtonBox.setPadding(new Insets(5, 0, 0, 0));

        hbButtonBox.setSpacing(10);

        hbButtonBox.getChildren().addAll(searchBox, criteriaBox, searchButton, btnClear);

        searchButton.setOnAction(new EventHandler() {

            public void handle(ActionEvent event) {

                btnSearchPressed(cb.getSelectionModel().getSelectedIndex(), searchText);
            }
        });

        primaryStage.setScene(scene);
        primaryStage.setVisible(true);

        tableItems = FXCollections.observableArrayList();

        tableView = new TableView(tableItems);

        TableColumn col1 = new TableColumn("Cust ID");
        TableColumn col2 = new TableColumn("First Name");
        TableColumn col3 = new TableColumn("Last Name");

        col1.setProperty("customerId");
        col2.setProperty("name");
        col3.setProperty("surname");

        tableView.getColumns().setAll(col1, col2, col3);

        vb.getChildren().addAll(hbButtonBox, tableView);

    }

    public void btnSearchPressed(int selection, TextBox searchText) {

        CustomerService customerService = BeanHelper.getBean(CustomerService.class);

        List customers = null;

        try {

            if (selection == 0) {

                if (searchText.getText() == null || searchText.getText().isEmpty()) {
                    tableItems.clear();
                    return;
                }
                Customer cust = customerService.getCustomer(Integer.valueOf(searchText.getText()).longValue());

                List list = new ArrayList();
                list.add(cust);

                customers = list;
            } else if (selection == 1) {
                customers = customerService.getCustomersByFirstName(searchText.getText());
            } else {
                customers = customerService.getCustomersByLastName(searchText.getText());
            }

            fillTable(customers);

        } catch (Exception ex) {
            tableItems.clear();
            Logger.getLogger(CustomerSearch.class.getName()).log(Level.SEVERE, null, ExceptionUtil.handleException(ex).getMessage());
        }

    }

    public void fillTable(List customers) {

        tableItems.clear();

        if (customers == null || customers.isEmpty()) {
            return;
        }

        ObservableList newItems = FXCollections.observableArrayList();

        for (int i = 0; i < customers.size(); i++) {

            CustomerFX p = new CustomerFX();

            Customer customer = customers.get(i);

            p.setName(customer.getName());
            p.setSurname(customer.getSurname());
            p.setCustomerId(Integer.valueOf((int) customer.getCustomerId()));

            newItems.add(p);
        }

        tableView.getItems().setAll(newItems);
    }
}






after successfull login, customer search page is displayed;  you can search customers according to customer id, name and last name.











Labels: , , , ,

Friday, June 10, 2011

Seahorse annotation driven RIA application development framework version 1.1 is released

Seahorse is an annotation driven framework that provides solutions for the model and controller layer of MVC based multiple rich internet applications (RIAs). Seahorse goals to provide all required functionality such as annotation driven dependency injection container (DIC), transaction management, persistency, caching, scheduling, authentication, remoting etc. to develop MVC based RIA applications. Seahorse can be used in distributed and collocated application architectures to develop Ajax based web applications and java rich client applications using JavaFX and Swing. Seahorse provides transparent remoting services to access to server side from rich client applications.



Followings are benefits of using Seahorse framework;

1. Declarative development environment for rapid application development

2. End to End solutions for the model and controller layer for the RIA applications

3. Annotation driven IOC container to easily configure and bind POJO beans

4. Declarative remote access and authentication for multiple rich clients

5. Declarative Transaction Management

6. Declarative server and client side caching

7. Declarative scheduling

8. JDBC abstraction layer that provides less coding and more robust development

9. Zero implementation to call stored procedures by providing declarative persistency

10. Highly customizable framework that almost you can change any framework implementation with the same approach that is used for configure applications



SeaHorse framework 1.1 tutorial, source code , binaries and sample project added to google code and can be downloaded from the following link : http://code.google.com/p/seahorse-ria-framework/

Labels: