Page Flow Basics: Retrieving and Displaying Data from a JDBC Data Source Using .JSP and BEA Page Flows

by Scott Semyan
03/28/2004

Most enterprise applications involve accessing data from a data store, modifying or filtering the data based on a user's request, and finally displaying that data to a user. Often the code for accessing, modifying and formatting the data for display is lumped together into a single component (for example, a Java servlet). As applications become more complex, it becomes increasingly difficult to maintain this undifferentiated code. The Model-View-Controller Java design pattern solves this problem by separating application functionality into three distinct roles:

  • The Model represents the business data and the rules associated with accessing and modifying the data (tables, views, database users, and so on)
  • The View is the user interface (Web pages, WAP interface, SOAP, and so on)
  • The Controller receives input from the user, translates that into requests for data, and then selects the appropriate view of that data for the user.

This pattern is the foundation of page flows. In a page flow, a client browser issues a request for information to the page flow via an HTTP get or post. The page flow (which acts as the controller) processes the user's request, and if applicable, issues a request for data from a database, legacy system, etc. (the model). The returned data then may be processed before it is sent to the appropriate JSP page for display (the View). This can be seen in the diagram below.

1


In this article I'll walk through an example of how to use the new page flow technology in WebLogic Workshop 8.0 beta to access the contents of a table from a database and display it to the user. I'll assume you have a data connection already set up correctly and that you are familiar with Java, JSPs, and TSQL. For this article I'll be using the cgDataSource that is included in the samples/workshop domain.

Start out by creating a new empty application in WebLogic Workshop called "DataTutorial". Be sure the new application is set to use the "samples/workshop" domain by right-clicking on it, selecting "Properties", and clicking the "WebLogic Server" section. The server home directory should point to "<install location>\weblogic81b\samples\workshop". Now start up the server by selecting "Tools/WebLogic Server/Start Server".

In your new application, right-click the "DataTutorial" folder and create a Web project called "ItemsTable." Right-click on the new ItemsTable project folder, choose "New/Choose File Type...", and select "Database Control" from the "Business Logic" group. This will take you to the Database control wizard. We'll call our new database control "DataModel", and we'll be using the cgDataSource. If you don't see the cgDataSource in the Data Source dropdown, make sure the server started correctly and that you are using the samples/workshop domain. Click next, select "Don't create methods", and click "Create". Usually it's nice to let the wizard create table access methods for you but to understand what is going on, we'll do it by hand.

Double-click on your new DataModel.jcx file in the datamodel folder and select "Source View". There are a few bugs we have to deal with. First, change the "data-source-jndi-name" from "DATA_SOURCE_JNDI" to "cgDataSource". Next, delete the schema the wizard adds. We won't be using it in this tutorial. Your DataModel control code should now look like this:


  package datamodel;

  import java.sql.SQLException;
  import javax.sql.RowSet;

  import weblogic.jws.control.DatabaseControl;
  import weblogic.jws.control.DatabaseFilter;

  /**
    *@jc:connection data-source-jndi-name="cgDataSource"
    */

  public interface DataModel extends DatabaseControl
  {
  }

Shortly, we'll add a method to get all rows from the "Items" table in the "Cajun" schema. But first, we need to create an "Item" object to easily access the data we get back. Right-click on the "datamodel" folder and select "New/Java Class". We'll call this class "Item". Each row in the Items table contains an item number, item name, quantity available, and a price. We'll add public members to our Item class to hold this information. For a real Java class, you will want to add getter, setter, and creator methods to handle setting and retrieving variables, but this isn't an article about Java class creation so we'll just do it the quick and easy way. Just remember to implement the "java.io.Serializable" interface so we can pass it into the request stream. Your Item.java file should look like this:


  package datamodel;

  public class Item implements java.io.Serializable
  {
      public Integer          ItemNumber;
      public String           ItemName;
      public Integer          QuantityAvailable;
      public Double           Price;
  }

Now we'll build a method in the database control to get all the rows from the Items table using our new Item class. In DataModel.jcx, go to Design View, right-click on the control, and add a new method named "getItems". Right-click on the new method and select "Edit SQL". This is where we put the SQL query to get the data we want. Put the following code in the SQL box to get all the columns from the Items table in the Cajun schema:


  SELECT ITEMNUMBER, ITEMNAME, QUANTITYAVAILABLE, PRICE FROM CAJUN.ITEMS

This will return all the items in the table, so we'll set the return type as an array of Items (from the Item class we built). Set the code in the Java box to this:


  public Item[] getItems()

Now if you go to Source View, the code for our DataModel control should look like this:


  package datamodel;

  import java.sql.SQLException;
  import javax.sql.RowSet;

  import weblogic.jws.control.DatabaseControl;
  import weblogic.jws.control.DatabaseFilter;

  /**
    *@jc:connection data-source-jndi-name="cgDataSource"
    */

  public interface DataModel extends DatabaseControl
  {

      /**
       * @jc:sql statement="SELECT ITEMNUMBER, ITEMNAME, QUANTITYAVAILABLE, PRICE
            FROM CAJUN.ITEMS"
       */
      public Item[] getItems();
  }

Now we are ready to use the control on a page flow. In the ItemsTable project you will see three files: index.jsp, error.jsp, and Controller.jpf. The controller file is the controller part of the Model-View-Controller pattern and the .JSP files are the views.

Double-click on Controller.jpf and make sure you are in "Flow View". Now, drag your DataModel.jsx onto the page flow. This will give you an instance of the control in the page flow you can access. Your page view should now look like this:

1


This diagram shows that new users coming into the page flow will first execute the 'begin' method (this is where we'll get the data from the database). We'll then put the data we receive from the database control into the request stream so it can be accessed by the index.jsp page. Notice the dataModel member in the palette. This means our DataModel database control is accessible from all the events in the page flow. Behind the scenes, WebLogic creates and deploys a Java servlet to control the actions on the page flow, but all we have to worry about is the basic code contained in the .jpf file.

Now switch to source view. Because we will be using our Item class, we need to add a reference to it in the imports section like so:


  import datamodel.Item;

We are finally ready to get our list of items out of the database. To do this we'll add code to access the getItems() method of our dataModel in the begin() method. We'll enclose our call to our database control in a try/catch block so that we can catch any errors and send them to the server window.


  protected Forward begin()
  {
     try
     {
         Item[] Items = dataModel.getItems();
         getRequest().setAttribute( "items", Items );
     }
     catch( Throwable ex )
     {
        ex.printStackTrace();
     }
     return new Forward("index");
  }

Notice we are calling the getItems() method in the database control and setting the return value to an array of Items. Now, to allow this array to be accessible from the .jsp page, we put it into the HTTP Request stream using setAttribute. If we wanted, we could access the dataModel variable right from the page flow, but the idea is to use the controller (the page flow) to control access to the data, deal with errors, and so on, and let the view (the JSP page) only have to worry about displaying the data. Our entire Controller.jpf should look like this:


  import com.bea.wlw.netui.pageflow.PageFlowController;
  import com.bea.wlw.netui.pageflow.Forward;
  import datamodel.Item;

  /**
   * This is the default controller for a blank web application.
   */
  public class Controller extends PageFlowController
  {
      /**
       * @common:control
       */
      private datamodel.DataModel dataModel;

      /**
       * @jpf:action
       * @jpf:forward name="index" path="index.jsp"
       */
      protected Forward begin()
      {
          try
          {
                  Item[] Items = dataModel.getItems();
                 getRequest().setAttribute( "items", Items );
          }
          catch( Throwable ex )
          {
                  ex.printStackTrace();
          }
          return new Forward("index");
      }
  }

Ok, we got the data from the database and put it into the request stream. Now we are ready to print out the list of items on our JSP page. Double click on index.jsp and go to Source View. Again, since we are using our Item class in this JSP, we need to reference it. In JSP you do this by putting an import statement at the top of the page like so:


  <%@page import="datamodel.Item"%>

Change the <title> to "Items Table" and add code so index.jsp looks like this:


  <!--Generated by Weblogic Workshop-->
  <%@ page language="java" contentType="text/html;charset=UTF-8"%>
  <%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
  <%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
  <%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
  <%@page import="datamodel.Item"%>

  <html>
    <head>
      <title>Items Table</title>
    </head>
    <body>
      Here is our Items Table:<p>
          <table border=1>
                  <tr><td>Item Number</td><td>Item Name</td><td>Quantity
                   Available</td><td>Price</td></tr>
                  <% // Get the Items from the request stream
                          Item oItem[] = (Item[]) request.getAttribute("items");

                          // Loop through the items
                          for (int f=0 ; f < oItem.length ; f++)
                          {
                                out.println("<tr><td>" + oItem[f].ItemNumber +
                                "</td><td>" + oItem[f].ItemName +
                                "</td><td>" + oItem[f].QuantityAvailable +
                                "</td><td>$" +  oItem[f].Price +
                                "</td></tr>");
                          }
                  %>
          </table>
    </body>
  </html>

Let's walk though the code. First we get the array of Items out of the request stream with this code:


  Item oItem[] = (Item[]) request.getAttribute("items");

Then we loop through the items:


  for (int f=0 ; f < oItem.length ; f++)

For each item, we print out the item number, item name, quantity available, and the price in table cells to the output stream:


  out.println("<tr><td>" + oItem[f].ItemNumber + "</td><td>" + oItem[f].ItemName +
  "</td><td>" + oItem[f].QuantityAvailable + "</td><td>$" + oItem[f].Price +
  "</td></tr>");

Because we used our Item object to store the columns from the Items table, we can easily access the objects members.

Now for the exciting part: select Debug/Start from the menu bar. Your machine will churn for a while as all the supporting servlets, beans, files, and so on, are built for the first time and deployed on the server. After a while, you should see this appear in the Workshop test browser:

1


If instead you got an error page, set a breakpoint on the first line of code in the begin method and rerun. As you step through the code, you should see where your error is.

Notice that the URL for our application is Controller.jpf, not index.jsp. As I said, the controller is actually a Java servlet that calls out to JSP files when it needs to render a display, but the core "controller" functionality is contained in the JPF. Our data access is encapsulated in the database control, and in a sense, on the database itself.

Although this is a simple example, you can see how easy it is to access data on a Web page and format it for the user. We separated the functions of our application into three distinct roles: the database control was our "model" – controlling access to the database and handing off results back from the database. The controller in our case was the aptly named Controller.jpf – the page flow itself. This piece handled requests from the user (the request for the main page in this case), asked for data from the Model, and formatted that data in a way it could be used by the view. Finally it passed on control to the view – index.jsp – that got the data and displayed it to the user. If the user requesting the data was using a cell phone browser, for example, our controller file could have easily directed to a different view for cell phones. Our database control can easily be reused in other page flows or in a Web service. Reusability is another benefit to using the MVC design pattern. For questions, bugs, or comments, contact dev2dev at dev2dev@bea.com.