Today you can find many articles showing Java EE 6 examples and new features. However it's missing a complete tutorial showing how to design and deploy a sample Java EE 6 application on JBoss AS 6. While it's not intended to be the "the right" way to design Java EE 6 applications, this tutorial can be helpful to show how some cool Java EE 6 features can combine to produce a simple but effective application.


The aim of this article will be to upgrade the Java EE 5 "AppStore" application, developed on JBoss AS 5, to Java EE 6. (You can download  the code for the earlier AppStore from Packtpub web site, or simply buy the book :-) )

The older EE 5 AppStore application was originally an Enterprise application made up of a Web Tier and EJB Tier.
The new EE 6 AppStore application is a Web application containing Web components, the Entity Models and the EJBs.


In order to set up this application, we will need at first to set up the Database schema.
java ee 6 tutorial
This schema was designed for MySQL 5. You will need just to create a schema named "Appstore" and
grant all privileges to the user "jboss"

CREATE DATABASE appstore;

USE appstore;

CREATE USER 'jboss'@'localhost' IDENTIFIED BY 'jboss';

GRANT ALL PRIVILEGES ON appstore TO  'jboss'@'localhost' WITH GRANT OPTION;

CREATE TABLE  `appstore`.`customer` (
`ID` int(10) unsigned NOT NULL auto_increment,
`NAME` varchar(45) NOT NULL,
`COUNTRY` varchar(45) NOT NULL,
PRIMARY KEY  (`ID`)
) ENGINE=InnoDB;
CREATE TABLE  `appstore`.`item` (
`ID` int(10) unsigned NOT NULL auto_increment,
`PRODUCT` varchar(45) default NULL,
`PRICE` int(11) default NULL,
`QUANTITY` int(11) default NULL,
`CUSTOMER_ID` int(10) unsigned NOT NULL,
PRIMARY KEY  (`ID`),
KEY `FK_orders` (`CUSTOMER_ID`),
CONSTRAINT `FK_orders` FOREIGN KEY (`CUSTOMER_ID`) REFERENCES `customer` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;


Once done with the DB schema, we will create a Datasource file pointing to the schema AppStore and
drop into the "deploy" folder of JBoss AS 6.

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <local-tx-datasource>
        <jndi-name>MySqlDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/appstore</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>jboss</user-name>
        <password>jboss</password>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
        </exception-sorter-class-name>
        <metadata>
            <type-mapping>mySQL</type-mapping>
        </metadata>
    </local-tx-datasource>
</datasources>

 

Good. Now the schema is completed, so let's build the Web application. Launch Eclipse.

From the Menu reach File | New | Dynamic Web Project

Choose the name AppStore for your Web application and leave the default Settings.

Now add to your Project the JSF 2.0 facets, by selecting Properties | Projects Facets

jsf 2.0 java ee 6 tutorial

Then, enable JSF 2.0 libraries and then instruct Eclipse where JBoss AS libraries are placed
(under "JBOSS_HOME\server\default\deployers\jsf.deployer")

jsf 2.0 jboss 6

Now let's bind the Datasource definition into our Web application by creating the persistence.xml into the WEB-INF/ folder

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="AppStore" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/MySqlDS</jta-data-source>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
        </properties>
    </persistence-unit>
</persistence>

Ok. Now it's time to build our classes. We will start from the model classes which map the database tables.
Building the Model
Here is the Customer class:

package model;

import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
import static javax.persistence.FetchType.EAGER;

@Entity
@Table(name = "customer")
public class Customer implements Serializable {
 private static final long serialVersionUID = 1L;
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "ID")
 private int id;
 @Column(name = "COUNTRY")
 private String country;
 @Column(name = "NAME")
 private String name;

 @OneToMany(mappedBy = "customerFK", fetch = EAGER)
 private List<Item> items;

 // Getters and setters here ...

}


and here is the Item class:

package model;

import java.io.Serializable;
@Entity
@Table(name="item")
public class Item implements Serializable {
 private static final long serialVersionUID = 1L;
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 @Column(name="ID")
 private int id;

 @Column(name="PRICE")
 private int price;
 @Column(name="PRODUCT")
 private String product;
 @Column(name="QUANTITY")
 private int quantity;
 //bi-directional many-to-one association to Customer
 @ManyToOne  
 @JoinColumn(name="CUSTOMER_ID")  
 private Customer customerFK;
 
 // Getters and setters here ...
}

 


 

Building the EJB tier

Now it's time to create our EJBs that will the facade to our Model.

Java EE 6 simplifies the application packaging by removing the restriction that enterprise bean classes must be packaged in an ejb-jar file. You can now place EJB classes directly in the .war file, using the same packaging guidelines that apply to web application classes.

ejb 3.1 jboss 6 jsf 2.0
As you can see from the above picture, the EJB used in this Web application are packed just as POJO in the Web application classes.

package ejb;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import model.Customer;
import model.Item;

@Stateless
public class StoreManagerDao {
 @PersistenceContext(unitName = "AppStore")
 private EntityManager em;

 public void createCustomer(String country, String name) {
   Customer customer = new Customer();
   customer.setCountry(country);
   customer.setName(name);
   em.persist(customer);
 }

 public void saveItem(int customerId, int price, int quantity, String product) {
   Customer customer = findCustomerById(customerId);
   Item order = new Item();
   order.setCustomerFK(customer);
   order.setPrice(price);
   order.setQuantity(quantity);
   order.setProduct(product);
   em.persist(order);
 }

 public List<Item> findAllItems(int customerId) {
   Query query = em.createQuery("FROM Customer where id=:id");
   query.setParameter("id", customerId);
   Customer customer = (Customer) query.getSingleResult();

   List<Item> customerOrders = customer.getItems();
   return customerOrders;
 }

 public Customer findCustomerByName(String customerName) {
   Query query = em.createQuery("FROM Customer where name=:name");
   query.setParameter("name", customerName);
   Customer customer = (Customer) query.getSingleResult();
   return customer;
 }

 public Customer findCustomerById(int id) {
   Query query = em.createQuery("FROM Customer where id=:id");
   query.setParameter("id", id);
   Customer customer = (Customer) query.getSingleResult();
   return customer;
 }

 public List<Customer> findAllCustomers() {
   Query query = em.createQuery("FROM Customer");
   List<Customer> customerList = query.getResultList();
   return customerList;
 }
}



This examples uses EJB 3.1 no-interface view. No interfaces EJB simplify the creation of your EJBs by making local business interfaces optional.

 


 

Building the JSF Managed Beans

Creating managed beans has never bean easier: you don't need any more declaring them in faces-config.xml. It's enough to declare them as annotation with the @ManagedBean annotation.

The first bean we will write is the @RequestScoped StoreManager JSF Bean which acts as a facade between the JSF page and the EJBs.

java ee 6 tutorial jboss 6

package control;

import java.util.*;

import javax.faces.application.FacesMessage;
import javax.faces.bean.*;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.inject.Inject;


import view.CustomerView;
import view.ItemView;

import ejb.StoreManagerDao;

import model.Customer;
import model.Item;

@ManagedBean()
@RequestScoped
public class StoreManager  {

 @Inject  
 private StoreManagerDao storeManager;

 @ManagedProperty(value="#{customerView}") 
 private CustomerView customerView;

 @ManagedProperty(value="#{itemView}") 
 private ItemView itemView;

 List<Item> listOrders;
 List <SelectItem> listCustomers;

 public StoreManager() {     }


// Getters and setters here ...


 public void findOrders() {  

   listOrders = storeManager.findAllItems(customerView.getCustomerId());

 }
 public void findAllCustomers() {  

   List<Customer> listCustomersEJB = storeManager.findAllCustomers();

   for (int ii=0;ii<listCustomersEJB.size();ii++) {
     Customer customer = listCustomersEJB.get(ii);
     listCustomers.add(new  SelectItem(customer.getId(),customer.getName()));

   }
 }

 public void saveOrder() { 
   storeManager.saveItem

         (customerView.getCustomerId(),itemView.getOrderPrice(),itemView.getOrderQuantity(),itemView.getOrderProduct());

   FacesMessage fm = new FacesMessage("Saved order for "+itemView.getOrderQuantity()+ " of "+itemView.getOrderProduct());
   FacesContext.getCurrentInstance().addMessage("Message", fm);

 }

 public void insertCustomer() {
  
   storeManager.createCustomer(customerView.getCustomerCountry(), customerView.getCustomerName());

   FacesMessage fm = new

      FacesMessage("Created Customer  "+customerView.getCustomerName()+ " from   "+customerView.getCustomerCountry());
   FacesContext.getCurrentInstance().addMessage("Message", fm);

   // Forces customer reloading
   this.listCustomers=null;
 }

 
 public List<SelectItem> getListCustomers() {
   if (listCustomers == null) {
     listCustomers= new ArrayList();
     findAllCustomers();
   }
   return listCustomers;
 }

 public void setListCustomers(List<SelectItem> listCustomers) {
   this.listCustomers = listCustomers;
 }
}


Things to notice:

1) The StoreManagerDao EJB is injected into the JSF Managed Bean using the annotation

@Inject  
private StoreManagerDao storeManager;


2) The other Managed Beans used in this project (to handle the form attributes) are injected using the @ManagedProperty annotation:

@ManagedProperty(value="#{customerView}") 
private CustomerView customerView;

@ManagedProperty(value="#{itemView}") 
private ItemView itemView;

 


 

The last beans we will add to our Projects are the CustomerView and ItemView which act as a vehicle between the JSF view and the Managed Beans.
java ee 6 tutorial

package view;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;
import javax.validation.constraints.*;

@ManagedBean(name="customerView")
@RequestScoped
public class CustomerView {
 @Size(min = 5, max=20, message = "Please enter a valid Customer name (5-20 characters)")
 @NotNull(message = "Please enter a Customer name")
 private String customerName;
 
 @Size(min = 5, max=20, message = "Please enter a valid Country (5-20 characters)")
 @NotNull(message = "Please enter a Country")
 private String customerCountry;
 
 private int customerId;
 
 public void customerListener(AjaxBehaviorEvent event) { 
   this.customerName = this.customerName.toUpperCase();
 }
 public void countryListener(AjaxBehaviorEvent event) { 
   this.customerCountry = this.customerCountry.toUpperCase();
 } 
 // Getters / Setters methods here
 
 }

 

package view;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;
import javax.validation.constraints.*;

@ManagedBean(name="itemView")
 
@RequestScoped
public class ItemView {
 @Min(value=0, message = "Order minimum 1 item") 
 @Max(value=1000, message = "Order maximum 1000 items") 
 private int orderQuantity;
 @Min(value=0, message = "Price cannot be less then 1") 
 private int orderPrice;
 @Size(min = 5, max=20, message = "Please enter a valid Product name (5-20 characters)")
 private String orderProduct;
 
 public void productListener(AjaxBehaviorEvent event) { 
   this.orderProduct = this.orderProduct.toUpperCase();
 } 

 // Getters / Setters methods here
 
}

Things to notice:
Both Beans use JSR 303 - bean validation, part of Java EE 6, which provides a mechanism to define data validation constraints in a way that is independent of the application tier.

 @Size(min = 5, max=20, message = "Please enter a valid Customer name (5-20 characters)")
 @NotNull(message = "Please enter a Customer name")
 private String customerName;

Both beans also use an AJAX listener which is triggered from the view pages when the user moves on to another field (onblur event).
The AJAX listener simply turns the text field into its uppercase equivalent.

 public void customerListener(AjaxBehaviorEvent event) { 
 this.customerName = this.customerName.toUpperCase();
 }     


Building the view using Facelets

This application uses Facelets as presentation technology technology for building JavaServer Faces.

Facelets emphasizes its ability to template content in your application. Templating promotes re-use and eases long term maintenance of your application, allowing content to be changed in one spot, but used in multiple pages.

Our template page, will contain an header, a central div and a footer.

jboss as 6 facelets

This is the template.xhtml file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

    <h:head>
        <style type="text/css">
            <!-- omitted for brevity -->
        </style>
    </h:head>

    <h:body>
        <div class="page">
            <div class="header">

                <ui:include src="/header.xhtml" />

            </div>

            <div class="content">

                <ui:insert name="content">
                </ui:insert>

            </div>
            <br />
            <div class="footer">

                <ui:include src="/footer.xhtml" />

            </div>
        </div>

    </h:body>
</html>


And this is the home.xhtml page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>

    </h:head>
    <h:body>
        <ui:composition template="../template.xhtml">
            <ui:define name="content">
                <h:panelGrid columns="1" styleClass="default">

                    <h:form id="listOrdersForm">
                        <h:outputText value="Select Customer:" />
                        <h:selectOneMenu id="selectCustomer" styleClass="buttons"
                            value="#{customerView.customerId}">
                            <f:selectItems value="#{storeManager.listCustomers}" />
                        </h:selectOneMenu>
                        <h:commandButton action="#{storeManager.findOrders}"
                            value="ListOrders" styleClass="buttons" />

                        <h:dataTable value="#{storeManager.listOrders}" var="orders"
                            styleClass="table" headerClass="table-header" rowClasses="table-odd-row,table-even-row">

                            <h:column>
                                <f:facet name="header">
                                    <h:outputText value="Product" />
                                </f:facet>
                                <h:outputText value="#{orders.product}" />
                            </h:column>
                            <h:column>
                                <f:facet name="header">
                                    <h:outputText value="Price" />
                                </f:facet>
                                <h:outputText value="#{orders.price}" />
                            </h:column>
                            <h:column>
                                <f:facet name="header">
                                    <h:outputText value="Quantity" />
                                </f:facet>
                                <h:outputText value="#{orders.quantity}" />
                            </h:column>

                        </h:dataTable>

                        <h:commandButton action="newCustomer" styleClass="buttons"
                            value="Insert Customer" />
                        <h:commandButton action="newOrder" styleClass="buttons"
                            value="Insert Order" />
                    </h:form>
                </h:panelGrid>
            </ui:define>
        </ui:composition>
    </h:body>
</html>

    
product-list
Things to notice:
1) One thing to notice is the <ui:composition> tag which tells that we are using the template.xhtml file as a template. Then, we are defining (through the <ui:define> tag) the content of the "content" section.

<ui:composition template="../template.xhtml">
   <ui:define name="content">
   </ui:define>
</ui:composition>        

2) All the navigation buttons contained in this application use implicit navigation: that is, since no navigation rule is defined in face-config.xml, they refer to the view that has the same name as the action: in our case to newCustomer.xhtml and newOrder.xhtml

<h:commandButton action="newCustomer" styleClass="buttons"
 value="Insert Customer" />
<h:commandButton action="newOrder" styleClass="buttons"
 value="Insert Order" />

The remaining part of this application are the newCustomer.xhtml and newOrder.xhtml views which are used respectively to create new Customers and new Orders:

Here's newCustomer.xhtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

    <h:body>
        <ui:composition template="../template.xhtml">
            <ui:define name="content">

                <h:form id="newCustomerForm">
                    <h:panelGrid columns="2" styleClass="default">
                        <f:facet name="header">
                            <h:outputText value="Insert new Customer" />
                        </f:facet>
                        <h:outputText value="Name" />
                        <h:inputText id="name" value="#{customerView.customerName}">
                            <f:ajax event="blur" render="name"
                                listener="#{customerView.customerListener}" />
                        </h:inputText>
                        <h:outputText value="Country" />
                        <h:inputText id="country" value="#{customerView.customerCountry}">
                            <f:ajax event="blur" render="country"
                                listener="#{customerView.countryListener}" />
                        </h:inputText>
                        <h:commandButton action="#{storeManager.insertCustomer}"
                            styleClass="buttons" value="Insert Customer" />

                    </h:panelGrid>
                    <h:messages />

                </h:form>
            </ui:define>
        </ui:composition>
    </h:body>
</html>

new-customer
Here's newOrder.xhtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

    <h:body>
        <ui:composition template="../template.xhtml">
            <ui:define name="content">
                <h:form id="newOrderForm">

                    <h:panelGrid columns="2" styleClass="default">
                        <f:facet name="header">
                            <h:outputText value="Insert new Order" />
                        </f:facet>
                        <h:outputText value="Product" />
                        <h:inputText id="name" value="#{itemView.orderProduct}">
                            <f:ajax event="blur" render="name" listener="#{itemView.productListener}" />
                        </h:inputText>

                        <h:outputText value="Quantity" />
                        <h:inputText value="#{itemView.orderQuantity}" />

                        <h:outputText value="Price" />
                        <h:inputText value="#{itemView.orderPrice}" />

                        <h:outputText value="Customer" />
                        <h:selectOneMenu id="selectCustomerforOrder"
                            styleClass="buttons" value="#{customerView.customerId}">
                            <f:selectItems value="#{storeManager.listCustomers}" />
                        </h:selectOneMenu>
                        <h:commandButton action="#{storeManager.saveOrder}"
                            styleClass="buttons" value="Save Order" />

                    </h:panelGrid>
                    <h:messages />
                </h:form>
            </ui:define>
        </ui:composition>
    </h:body>
</html>

new-order
Things to notice:
The inputText fields are bound to a JSF 2 Ajax listener which is triggered when the blur event is triggered.As we have seen, the purpose of this listener is to simply uppercase the text field.

<h:inputText id="name" value="#{customerView.customerName}">
 <f:ajax event="blur" render="name"
 listener="#{customerView.customerListener}" />
 </h:inputText>        

Well that's all folks! All you need to do is deploying the Web application on JBoss AS 6. For the sake of brevity some smaller parts (header.xhtml, footer.xhtml) were omitted, however you can download the full Eclipse Project from here:

Download code here !

0
0
0
s2sdefault