DevelopJavaEE6App

Contents

Develop JavaEE 6 application with JSF2, EJB3 and JPA

Introduction

This document is an update from the tutorial, Develop JavaEE5 Application with Visual JSF, EJB3 and JPA.

Like the previous tutorial, it describes the detail steps to develop a web-based application, but this time, it is based on technologies in the JEE6 specs, i.e. JavaServer Faces 2.0 (JSF), Enterprise Java Beans 3.1 (Session Bean and Message-Driven Bean) and Java Persistence API (JPA) with the help of Netbeans 6.8 (Beta) IDE as the tool. Again, this tutorial creates a web application called CustomerApp that performs only the Retrieve and Update functions of (CRUD) on the customer records provided by the Netbeans sample database served by the Glassfish built-in database server, JavaDB (Derby). In addition, it also demonstrate the use of Message-Driven Bean (MDB) for asynchronous messaging.

The objective of this tutorial is to demonstrate the ease of using several JEE6 technologies like JSF2.0, EJB3 and JPA with the help of Netbeans IDE and putting them together to create an enterprise-ready web-based application. Although the application is developed for demo purpose, its architecture represents the best practice in developing an Enterprise application, whereby modularity, scalability and reusability are taken into consideration.

File:2-1-Architecture.gif

The application is organized into the various tiers: Presentation, Business, Data Access and Data, where each has an important role to play and are segregated from one another. This architecture encourages clean separation of responsibilities, reusability and scalability through the use of Enterprise Java Beans. With the use of JSF and JPA, GUI development becomes a breeze and developers are no longer bogged down by the tedious and error-prone chores of converting Relational data to OO which is natural in Java and vice versa.

So all-in-all, this demo not only demonstrates the use of the various JEE6 technologies, it also demonstrates the best-of-breed application architecture that can be used in a production system.

Contents

Tutorial Requirements

Before we proceed, make sure you review the requirements in this section.

Prerequisites

This tutorial assumes that you have some basic knowledge of, or programming experience with, the following technologies.

  • JavaServer Faces (JSF)
  • Enterprise Java Beans 3 (EJB3)
  • Java Persistence API (JPA)
  • Basic knowledge of using Netbeans (will help to reduce the time required to do this tutorial)

Software needed for this Tutorial

Before you begin, you need to install the following software on your computer:

  • Netbeans IDE 6.8 (Java pack)
  • Glassfish Enterprise Server v3 (b73 or later)
  • Sample database installed along with Netbeans

    File:2-2-DBSetup.png

Notes

  • The Glassfish Enterprise Server is optionally included in the Java pack of Netbeans IDE, Glassfish can be installed separately from the IDE and added later into Servers services in the IDE
  • A copy of the working solution is included here if needed.

Creating the Enterprise Application Projects

The first step in creating the application is to create the necessary projects in Netbeans.

  1. Choose “File > New Project” to open the New Project Wizard. Under Categories, select Java EE; under Projects select Enterprise Application. Click Next
  2. Select the project location and name the project, CustomerApp, and click Next
  3. Select the installed Glassfish v3 as the server, and Java EE 6 as the Java EE Version, and click Finish
    Netbeans will create 3 projects namely CustomerApp (Enterprise Application project), CustomerApp-ejb (EJB project) and CustomerApp-war (Web project).

    File:2-3-Projects.png

Creating the Entity Classes from the Database

Before anything else, we first need to create the Entity Classes and because in this demo, the Session Beans are responsible for manipulating the data, they will be created in the EJB project.

  1. In the Projects view, right-click on the CustomerApp-ejb project and select “New > Entity Classes from Database…”
  2. Select Data Source (Radio button) and in the corresponding dropdown list, select New Data Source…
  3. Specify the JNDI name to be “jdbc/sample”, and select “jdbc:derby://localhost:1527/sample [app on APP]” as the Database Connection and click OK
  4. Under the Available Tables list box, select CUSTOMER and click on Add button so that it appears in the Selected Tables list box (Note that the related table, DISCOUNT_CODE is also added automatically) and click Next

    File:2-4-NewEntityClasses.png
  5. Click on the “Create Persistence Unit...” button, select “jdbc/sample” as the Data Source; leave the rest as default and click Create

    File:2-5-CreatePU.png
  6. Provide a package name, e.g. “com.customerapp.entity” in the Package field and click Next
  7. Change the Collection Type to “java.util.List” and click Finish
  8. Take note of the new classes created under the Source Packages in the Projects view

    File:2-6-EntityClasses.png

Creating the Enterprise Java Beans (Session and Message-Driven)

Now that we have the Entity classes, the next task is to create the Session (Stateless) Bean, CustomerSession that will manipulate and provide the RU functionalities on the Customer objects. In this demo, the client that uses these functions are the JSF pages. One of the benefits of doing this (i.e. to provide the functionalities in the EJB layer) is reusability because the same functions can be used by more than one JSF pages, other EJBs, Enterprise Application Clients and Web Services Clients when exposed as web services. Other benefits include scalability because the EJB container can easily be tuned and scaled up when load increases.

We will also create a Message-Driven Bean (MDB), NotificationBean here to demonstrate its use for asynchronous messaging. In this tutorial, we want to send out notifications upon a successful update of a Customer record. For simplicity, we are just sending the updated Customer object to the Queue, so that the MDB can pick it up and process it in a separate thread.

  1. In the Projects view, right-click on the CustomerApp-ejb project and select “New > Session Bean...”
  2. In the New Session Bean dialog, specify the EJB Name as CustomerSession, the package as “com.customerapp.ejb”, Session Type as Stateless and leave Create Interface unchecked, i.e. no Interface (New in EJB 3.1), and click Finish

    File:2-7-NewSessionBean.png
  3. In the Projects view again, right-click on the CustomerApp-ejb project and select "New > Message-Driven Bean..."
  4. In the New Message-Driven Bean dialog, specify the EJB Name as NotificationBean and the package as "com.customerapp.mdb", click on the "Add..." button of the Project Destination option
  5. In the Add Message Destination dialog, specify the Destination Name as NotificationQueue and keep the Destination Type as Queue and click OK

    File:2-8-NewMDB.png

    Click Finish to complete the creation of the MDB
  6. From the Projects view, navigate to the source of the newly created Session Bean (skeleton) by double clicking on the CustomerSessionBean item

    File:2-9-CustomerSessionBean.png
  7. In the code editor, right-click and select “Persistence > Use Entity Manager”; the “@PersistenceContext” notation is inserted automatically, so now the EntityManager, with variable name, em is ready to be used
  8. Create the business methods for the Session Bean: Retrieve and Update; right-click in the code editor, select Insert Code..., under the Generate list, select Add Business Method…
  9. In the Add Business Method... dialog, provide the Name, Return Type and Parameters for the method

    File:2-10-AddBizMethod.png
  10. Repeat the steps for the Update function.
  11. Edit the methods so that they implement the intended functions as shown below
@Stateless
@LocalBean
public class CustomerSessionBean
{
    @PersistenceContext
    private EntityManager em;

    /**
     * Returns a list of Customer objects in the database
     * @return List<Customer>
     */
    public List<Customer> retrieve()
    {
        Query query = em.createNamedQuery("Customer.findAll");
        return query.getResultList();
    }

    /**
     * Update the customer record
     * @param customer object to be updated
     * @return Customer
     */
    public Customer update(Customer customer)
    {
        return em.merge(customer);
    }
}
Now we will add the code to send the updated Customer object to the destination queue

12. In the code editor, right click and select "Insert Code...", and "Send JMS Message" from the Generate list

13. In the Send JMS Message dialog, select "jms/NotificationQueue" as the Project Destination and click OK

Notice the 2 auto-generated methods, createJMSMessageForjmsNotificationQueue and sendJMSMessageToNotificationQueue

14. In the update method, insert code to call the sendJMSMessageToNotificationQueue after the em.merge() statement and modify the createJMSMessageForjmsNotificationQueue method to send ObjectMessage instead
    @Resource(name = "jms/NotificationQueue")
    private Queue notificationQueue;
    @Resource(name = "jms/NotificationQueueFactory")
    private ConnectionFactory notificationQueueFactory;

    public Customer update(Customer customer)
    {
        Customer updated = em.merge(customer);
        try
        {
            sendJMSMessageToNotificationQueue(updated);
        }
        catch (JMSException ex)
        {
            Logger.getLogger(CustomerSessionBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Customer updated in CustomerSessionBean!");
        return updated;
    }

    private Message createJMSMessageForjmsNotificationQueue(Session session, Object messageData) throws JMSException
    {
        //Modified to use ObjectMessage instead
        ObjectMessage tm = session.createObjectMessage();
        tm.setObject((Serializable) messageData);
        return tm;
    }

    private void sendJMSMessageToNotificationQueue(Object messageData) throws JMSException
    {
        Connection connection = null;
        Session session = null;
        try
        {
            connection = notificationQueueFactory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(notificationQueue);
            messageProducer.send(createJMSMessageForjmsNotificationQueue(session, messageData));
        }
        finally
        {
            if (session != null)
            {
                try
                {
                    session.close();
                }
                catch (JMSException e)
                {
                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
                }
            }
            if (connection != null)
            {
                connection.close();
            }
        }
    }
15. In the Message-Driven Bean, NotificationBean, edit the onMessage method to simply print the details of the updated Customer object to show that it receives the message.

Note: typically you would not want to process the message in the MDB itself, the MDB should invoke method in another Session Bean to perform the processing, but for the purpose of demonstration in this tutorial we are stopping at the MDB
    public void onMessage(Message message)
    {
        try
        {
            Object msgObj = ((ObjectMessage)message).getObject();
            if (msgObj != null)
            {
                Customer customer = (Customer)msgObj;
                System.out.println("Customer with the following details has been updated:");
                StringBuilder sb = new StringBuilder();
                sb.append("Customer ID=");
                sb.append(customer.getCustomerId());
                sb.append(", ");
                sb.append("Name=");
                sb.append(customer.getName());
                sb.append(", ");
                sb.append("Email=");
                sb.append(customer.getEmail());
                System.out.println(sb.toString());
            }
        }
        catch (JMSException ex)
        {
            Logger.getLogger(NotificationBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
Up to this point, the tasks required to be done in the EJB project are completed, we will move on to the next tier, JSF pages.

Preparing the Web Project to use JavaServer Faces (JSF) 2.0

Before creating the web pages, ensure the JavaServer Faces framework is added to the Web project, CustomerApp-war.

  1. In the Projects view, right-click on the Web project, CustomerApp-war, and select Properties (last item)
  2. Under the Categories items, select Frameworks, and ensure the JavaServer Faces is added to the Used Frameworks list

    File:2-11-AddJSFSupport.png

In the sections below, you will create the JSF pages to present the screens to perform the Read/Update functions. To achieve this, we will be creating 2 web pages:

  • CustomerList – listing of all Customer records in the database in a tabular form
  • CustomerDetails – view/edit the details of the selected Customer record

Creating the Customer Managed Bean

Before creating the JSF pages, we first create the managed bean which will be providing the required services for the JSF pages that will be created later.

  1. In the Projects view, right-click on the Web project, CustomerApp-war, and select “New > JSF Managed Bean...”, specify CustomerMBean as the Class Name, "com.customerapp.web" as the Package Name, customer as the Name, and the scope to be session

    File:2-13-NewJSFMBean.png
  2. In the code editor of the newly created class, CustomerMBean, right-click and select "Insert Code...", and “Call Enterprise Bean...” under the Generate list
  3. In the "Call Enterprise Bean" dialog, expand the CustomerApp-ejb project and select the CustomerSessionBean and select the No Interface option (anyway the Local and Remote options should be disabled because we created the Session Bean with no interface) for Referenced Interface, and click OK
  4. Notice the automatically generated variable, customerSessionBean that represents an instance of the session bean, at the beginning of the class declaration.

    Add the rest of the methods (properties and action handlers) and its implementations in the class as shown below, they will be used by the JSF pages later
@ManagedBean(name="customer")
@SessionScoped
public class CustomerMBean
{
    @EJB
    private CustomerSessionBean customerSessionBean;
    private Customer customer;

    public CustomerMBean()
    {
    }

    /**
     * Returns list of customer objects to be displayed in the data table
     * @return
     */
    public List<Customer> getCustomers()
    {
        return customerSessionBean.retrieve();
    }

    /**
     * Returns the selected Customer object
     * @return
     */
    public Customer getDetails()
    {
        //Can either do this for simplicity or fetch the details again from the
        //database using the Customer ID
        return customer;
    }
    
    /**
     * Action handler - user selects a customer record from the list
     * (data table) to view/edit
     * @param customer
     * @return
     */
    public String showDetails(Customer customer)
    {
        this.customer = customer;
        return "DETAILS";
    }

    /**
     * Action handler - update the changes in the Customer object to the
     * database
     * @return
     */
    public String update()
    {
        System.out.println("###UPDATE###");
        customer = customerSessionBean.update(customer);
        return "SAVED";
    }

    /**
     * Action handler - goes to the Customer listing page
     * @return
     */
    public String list()
    {
        System.out.println("###LIST###");
        return "LIST";
    }
}

Creating the Customer Listing Web Page

Now, we are ready to create the first web page that lists the Customer records in the database in a tabular form.

  1. In the Projects view, right-click on the Web project, CustomerApp-war, and select “New > JSF Page...”, specify CustomerList as the File Name and JSP File under the Options

    File:2-12-NewJSF.png
  2. In the code editor, drag item, "JSF Data Table from Entity" from the palette and drop it in between the <body></body> tags of the newly generated file, CustomerList.jsp

    File:2-14-DragDataTable.png
  3. A dialog with the title, "JSF Table from Entity" appears; select "com.customerapp.entity.Customer" as the Entity Bean, and "customer.customers" as the Managed Bean property and click OK

    File:2-15-JSFTableFrmEntity.png

    Notice the result of this are lines of codes automatically generated to display a default list of the Customer objects
  4. At this point, we are ready to see the result of the first web page created so far. In the Projects view, right-click on the CustomerApp project and select Clean and Build, and select Deploy. To confirm that the deployment is successful, navigate to the Applications folder in the Glassfish server under the Services view and check if the application, CustomerApp exist

    File:2-16-Glassfishv3.png
  5. Open the browser and go to URL, http://localhost:8080/CustomerApp-war/faces/CustomerList.jsp and you should see the following screen



    Notice the screen is very raw and without any beautification, so we can beautify the screen a little with the use of stylesheets and modify the JSP to show only the columns of interest
  6. Add the followings in the stylesheet file, css/default.css
    th {
        background-color: #0000ff;
        color: #fafafa;
    }

    tr.tab_odd_row {
        background-color: #fefeff;
        color: #4e6a71;
    }

    tr.tab_even_row {
        background-color: #eff5fa;
        color: #4e6a71;
    }
7. Include the stylesheet in the JSP in the <head> using the <link> tag, and modify the code to look like the following:
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Customer Listing</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body >
            <h1><h:outputText value="Customer Listing"/></h1>
            <h:panelGrid cellspacing="3">
            <h:form>
            <h:dataTable value="#{customer.customers}" var="item"
                         border="1" cellspacing="0" cellpadding="1"
                         rowClasses="tab_odd_row,tab_even_row">
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="CustomerId"/>
                    </f:facet>
                    <!-- Replace outputText with commandLink here to navigate 
                    to the details page -->
                    <h:commandLink action="#{customer.showDetails(item)}"
                                   value="#{item.customerId}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Name"/>
                    </f:facet>
                    <h:outputText value="#{item.name}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="CreditLimit"/>
                    </f:facet>
                    <h:outputText value="#{item.creditLimit}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Discount %"/>
                    </f:facet>
                    <h:outputText value="#{item.discountCode.rate}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="State"/>
                    </f:facet>
                    <h:outputText value="#{item.state}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="City"/>
                    </f:facet>
                    <h:outputText value="#{item.city}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Zip"/>
                    </f:facet>
                    <h:outputText value="#{item.zip}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Phone"/>
                    </f:facet>
                    <h:outputText value="#{item.phone}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Email"/>
                    </f:facet>
                    <h:outputText value="#{item.email}"/>
                </h:column>
            </h:dataTable>
            </h:form>
            </h:panelGrid>
        </body>
    </html>
</f:view>
The result of the changes should look like this:



Now that we have the listing page, let's move on to create the details page.

Creating the Customer Details Web Page

Now we will create the page where the details of the selected customer is displayed and can be updated.

  1. In the Projects view, right-click on the Web project, CustomerApp-war, and select “New > JSF Page...”, specify CustomerDetails as the File Name and JSP File under the Options
  2. In the code editor, drag the item, "JSF Form from Entity" from the palette and drop it in between the <body></body> tags of the newly generated file, CustomerDetails.jsp

    File:2-17-DragJSFForm.png
  3. A dialog with the title, "JSF Form from Entity" appears; select "com.customerapp.entity.Customer" as the Entity Bean, and "customer.details" as the Managed Bean property and click OK

    File:2-17-NewJSFForm.png

    Notice the result of this are lines of codes automatically generated to display label and input field of all the attributes in Customer object in a 2 columns grid.
  4. To enable the navigation from the Listing page to the Details and vice versa, you need to edit the faces-config.xml with the PageFlow editor and connect the 2 pages as shown in the diagram below

    File:2-18-PageFlow.png

    • Notes: the <from-outcome> strings LIST and DETAILS must match the return String of the list and showDetails methods in the CustomerMBean
  5. To see the result, save and deploy the application, go to the Customer listing page at URL, http://localhost:8080/CustomerApp-war/faces/CustomerList.jsp, and click on the Customer ID on the first row in the table

    File:2-17a-CustomerDetails.png

    Again, this looks very raw, so let's try to spice it up a little and include the Update function as well
  6. The Discount Codes is a fixed list in the database, so it makes sense to present it in the form of a dropdown list for user to select for Update. So we will bind the value of the <f:selectItem> of the Discount Codes dropdown list to a new property, customer.discountCodes in CustomerMBean which returns an array of SelectItem(Object value, String label)
    /**
     * Returns an array of SelectItem to be displayed in the DiscountCode
     * Dropdown list in the CustomerDetails page
     * @return
     */
    public javax.faces.model.SelectItem[] getDiscountCodes()
    {
        SelectItem[] options = null;
        List<DiscountCode> discountCodes = customerSessionBean.getDiscountCodes();
        if (discountCodes != null && discountCodes.size() > 0)
        {
            int i = 0;
            options = new SelectItem[discountCodes.size()];
            for (DiscountCode dc : discountCodes)
            {
                options[i++] = new SelectItem(dc.getDiscountCode(),
                        dc.getDiscountCode() + " (" + dc.getRate() + "%)");
            }
        }
        return options;
    }
Notice the value of each SelectItem is the Discount Code of type Character, as such, the value to be bounded to the Discount Code <h:selectOneMenu> needs to be of type Character for the preselect to work when the details of a customer is being displayed. So we will need to create the getter and setter methods for a new property, discount in the Customer Entity class, which uses Character as the argument
    //New getter and setter methods for discount in Customer.java

    public Character getDiscount()
    {
        return this.discountCode.getDiscountCode();
    }

    public void setDiscount(Character code)
    {
        this.discountCode = new DiscountCode(code);
    }
7. Bind this new property, "customer.details.discount" to the value of the <h:selectOneMenu> of the Discount Code field in the CustomerDetails.jsp
    <h:selectOneMenu id="discountCode" value="#{customer.details.discount}">
        <f:selectItems value="#{customer.discountCodes}"/>
    </h:selectOneMenu>
8. Make the rest of the changes to the JSP page with the help of the code completion feature of Netbeans:
  • Add the <link> tag in the <head> to include the stylesheet, css/default.css
  • Add the Command buttons, <h:commandButton> for Update and Back
  • Rearrange the rows and use a different background color for the panelGrid
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Customer Details</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body>
            <h1><h:outputText value="Customer Details"/></h1>
        <h:form>
            <h:panelGrid columns="2" cellspacing="3" cellpadding="3" bgcolor="#eff5fa">
                <h:outputLabel value="Customer ID:"/>
                <h:inputText id="customerId" value="#{customer.details.customerId}" disabled="true"/>
                <h:outputLabel value="Customer Name:"/>
                <h:inputText id="customerName" value="#{customer.details.name}"/>
                <h:outputLabel value="Credit Limit:"/>
                <h:inputText id="creditLimit" value="#{customer.details.creditLimit}"/>
                <h:outputLabel value="Discount Code"/>
                <h:selectOneMenu id="discountCode" value="#{customer.details.discount}">
                    <f:selectItems value="#{customer.discountCodes}"/>
                </h:selectOneMenu>
                <h:outputLabel value="Email:"/>
                <h:inputText id="email" value="#{customer.details.email}"/>
                <h:outputLabel value="Phone:"/>
                <h:inputText id="phone" value="#{customer.details.phone}"/>
                <h:outputLabel value="Fax:"/>
                <h:inputText id="fax" value="#{customer.details.fax}"/>
                <h:outputLabel value="Address (Line 1):"/>
                <h:inputText id="address1" value="#{customer.details.addressline1}"/>
                <h:outputLabel value="Address (Line 2):"/>
                <h:inputText id="address2" value="#{customer.details.addressline2}"/>
                <h:outputLabel value="State:"/>
                <h:inputText id="state" value="#{customer.details.state}"/>
                <h:outputLabel value="City:"/>
                <h:inputText id="city" value="#{customer.details.city}"/>
                <h:outputLabel value="Zip:"/>
                <h:inputText id="zip" value="#{customer.details.zip}"/>
        </h:panelGrid>
            <h:commandButton id="update" value="Update" action="#{customer.update}"/> 
            <h:commandButton id="back" value="Back" action="#{customer.list}"/>
            </h:form>
        </body>
    </html>
</f:view>
The result of the changes should look like this:

File:2-17b-CustomerDetails.png

Now try the Update function by clicking on the Update button and you should see something similar to the following in the log file, server.log
[#|2009-11-30T14:42:50.550+0800|INFO|glassfishv3.0|...|_ThreadID=28;_ThreadName=Thread-1;|Customer updated in CustomerSessionBean!|#]

[#|2009-11-30T14:42:50.950+0800|INFO|glassfishv3.0|...|_ThreadID=20;_ThreadName=Thread-1;|Customer with the following details has been updated:|#]

[#|2009-11-30T14:42:50.950+0800|INFO|glassfishv3.0|...|_ThreadID=20;_ThreadName=Thread-1;|Customer ID=1, Name=JumboCom 2, Email=jumbocom@gmail.com|#]
Notice the statement "Customer updated in CustomerSessionBean" although printed in the Session Bean (ThreadID=28) after invoking the send JMS message, appears before the next two lines which are printed in the Message-Driven Bean in ThreadID=20

Summary

Congratulation, by now you should have a fully working application with the RU functionalities. Using the same approach and methods, you can expand the application into a full-fledged enterprise application with little effort. If you cannot get your application to work like how it is supposed to be, not to worry, you can get a copy of the working solution from here.

This tutorial demonstrates the use of various JEE6 technologies (JSF2.0, EJB3 & JPA) to build an enterprise-ready web-based application. Although the same application can be achieved easily by using JSF and JPA alone, but it may not be as scalable and reusable as what is being done here. In this tutorial, the application is segregated into different tiers where each does what they do best: presentation, business logics and data access. This promotes the principle of separation of concerns and each tier can change without effecting the other, e.g. we can change the JSF piece to use ICEfaces as the presentation tier if needed later.

Good luck with your next JEE application!

--Christopherlam 06:28, 8 December 2009 (UTC)

See Also

For other related resources, see the followings:

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo