Adding a Web Interface to the Agency Case Study

Now that you have seen many of the features of JavaServer Pages, you are in a position to add a Web front-end to the Agency case study. You will only develop a simple, but functional, Web interface; it may not be too pretty, but it will work.

NOTE

The examples shown in the remainder of this chapter and on the accompanying Web site have been written to the JSP 1.2 specification (without using the EL). On Day 14, you will refactor this code to use JSTL and the Element Language. If you are unlikely to be working with 1.2 JSPs you can skip these examples and today's exercise and move straight on to Day 14.


Designing a complete Web site is as much an art as a science, and what is considered good design by one developer may not be well-regarded by another. You, too, will have your own views about what comprises a “good” Web site. Rather than get into the aesthetics of Web site design, this section will concentrate on applying the features of JSP in an effective manner.

Structure and Navigation

Designing a good Web site is a lot like designing good Java code. Both require careful logical thought and should incorporate good design principles and practices. A well-designed Java program is easier to maintain and enhance than a badly designed one. Similarly, a well-designed Web site is easy for users to navigate and use. A well-designed Web site will have proportionally less complaints and criticisms than a badly designed site.

In this section, you will only look at the logical structuring and layout of the Web pages and Web applications. The presentation of the page (its look and feel) is a very emotive subject, and what appeals to one user may not appeal to another. Furthermore, your Web page look and feel will almost certainly be constrained (or dictated) by departmental or corporate standards. The structuring of your Web site may well be guided by local standards or conventions, but even so, you can apply logic and some simple guidelines to improve the navigability and use of the Web site as a whole.

Consider structuring your Web site along the same lines as you store your files in directories. This way, you can use different Web applications to represent different functional areas of your systems, and use the Web application context and aliases to simplify navigation.

Some simple guidelines for good site layout are as follows:

  • Group logically related functionality in a single Web application. By grouping related functionality into one application, you can reduce the learning time required for someone to maintain or link into your application because he or she only needs to study part of the site rather than the whole lot.

  • Use Web component aliases to apply a structure to your Web pages. Consider using multiple aliases for a Web page so that multiple aliases can point to a single page, allowing for logical hierarchical naming conventions. The Agency case study used names to relate functionality by area as follows:

    /customer/create
    /customer/delete
    

    The aliases could just as easily have related logically similar functionality such as

    /delete/customer
    /delete/applicant
    

    Alternatively, both naming schemes could have been provided. It all depends on how you view the inter-relationships between the various pages in your application.

    Whatever approach you choose, you should always use aliases and not the actual JSP names. This will allow you to restructure your Web site by adding, removing, or renaming JSP files without affecting hyperlinks from other pages.

    • Ensure that no Web pages are dead ends (have no links to another page).

    • Provide navigation links in the same place on every page.

    • Ensure that every page has a link back to your site's home page and, if appropriate, a link to the top level page for this logical area of your system.

The Agency case study has the following logical areas:

  • Customers advertising jobs

  • Applicants registering their locations and skills

  • Administration of the location and skill lookup tables

Looking ahead to Day 15, “Security,” when you will study the role of security within a J2EE application, you can structure your Web application to simplify the implementation of Web page authorization. You will do this by grouping all job and customer functionality under URLs starting with customer as follows:

/customer/advertise
/customer/createCustomer
/customer/deleteCustomer
/customer/updateCustomer

You will also store applicant functionality under pages with URLs starting with applicant as follows:

/applicant/register
/applicant/createApplicant
/applicant/deleteApplicant
/applicant/updateApplicant

A Web site will typically have a main page, often called the home page (also known as the portal page or index page), that provides access to the functionality of the Web application. All clients will have access to the home page, but they may have to log in to use other features of the application. Because J2EE Web authorization is based on URL patterns, intelligent use of aliases for each Web page can ease the implementation of security to the Web application (as discussed on Day 15).

It is usual to make the home page the default page when browsing to the Web application by adding it as a welcome page.

The Agency case study will have a home page that will allow:

  • An existing customer to access his or her own details

  • A new customer to be added to the system

  • An existing applicant access to his or her own details

  • A new applicant to register his or her details

  • Access to administration features

You will start by studying some features of the main page for Job Agency application. The “Deploying the Case Study JSPs” section, later in this chapter, shows you how to deploy the code you will study.

Look and Feel

Using a consistent look and feel across Web pages is an important principle. Consistent look and feel is supported by using the JSP include directive and HTML Cascading Style Sheets (CSS).

JSP include directives can be used to define common features for all pages, such as headers, footers, and navigation links. These directives can be used instead of server-side include directives implemented by some Web servers.

An example of how to use include files is shown in the following code fragment:

<HTML>
<HEAD>
<TITLE>Agency Portal</TITLE>
<%@include file="header.jsf" %>
<!-- rest of page -->

Each Web page in the case study will include a common header file, shown in Listing 13.11.

Listing 13.11. Full Text of header.jsf
<%@page errorPage="/agency/errorPage.jsp" %>
<LINK rel=stylesheet type="text/css" href="/agency/agency.css">
</HEAD>
<BODY>
  <jsp:useBean id="agency" class="web.AgencyBean" scope="request" />
  <H1><jsp:getProperty name="agency" property="agencyName"/></H1>

Note that this file uses the jsf extension to show it is not a complete JSP. The header file defines an error page, a style sheet, and a common page heading that includes the job agency name.

By structuring the Web pages to include a common header file, you can be sure there will be a common look and feel to each page. The header file completes the page <HEAD> section and starts the page <BODY>. This isn't ideal, because the JSP designer has to know that the include file spans two logical components of the HTML page (it would be better to make this two header files, one with the tags to be included in the <HEAD> tag and one with those for the <BODY> tag). But it does serve to show how useful include files can be.

The included header file also defines a bean called agency that can be used on the rest of the page to access the agency Session EJB. The level 1 page heading (<H1>) uses the agency name obtained from the agency bean.

If you haven't encountered HTML style sheets before, the simple one used for the agency is shown in Listing 13.12.

Listing 13.12. Full Text of agency.css
H1, H2, H3 {font-family: sans-serif}
H1 {background-color: navy; color: white }
H2 {color: navy }
H3 {color: blue }
BODY, P, FORM, TABLE, TH, TD {font-family: sans-serif}

Without going into detail, all this style sheet does is define font styles and colors for use with the HTML tags on a Web page that links to this style sheet. Older browser support for CSS is erratic, so you may not see all of the desired font changes with your browser if you are not using one of the latest CSS specification compliant browsers.

Returning to the agency portal page, you can use the agency bean defined by the header to access the agency Session EJB functionality. When the user clicks the Show Customer button, the following JSP fragment presents the user with a list of customer names and invokes an advertise.jsp page (via its alias customer/advertise).

<FORM action="customer/advertise">
<TABLE>
<TR><TD>Select Customer</TD>
<TD><SELECT name="customer">
<% Iterator customers = agency.getCustomers().iterator(); %>
<% while (customers.hasNext()) {%>
  <OPTION><%=customers.next()%></OPTION>
<% } %>
</SELECT>
</TD></TR>
<TR><TD colspan="2"><input type="submit" value="Show Customer"></TD></TR>
</TABLE>
</FORM>

The HTML select tag used on this form, and later examples, has been encoded as a scriptlet. On Day 14, you will see how JSTL can be used to achieve the same flow of control.

Listing 13.13 shows all the code of the portal page for the Agency application with support for the customer functionality only.

Listing 13.13. Full Text of agency.jsp
<HTML>
  <HEAD>
  <TITLE>Agency Portal</TITLE>
  <%@include file="header.jsf" %>
  <%@page import="java.util.*" %>
    <H2>Customers</H2>
    <H3>Existing Customer</H3>
    <FORM action="customer/advertise">
      <TABLE>
        <TR><TD>Select Customer</TD>
        <TD><SELECT name="customer">
        <% Iterator customers = agency.getCustomers().iterator(); %>
        <% while (customers.hasNext()) {%>
        <OPTION><%=customers.next()%></OPTION>
        <% } %>
        </SELECT>
        </TD></TR>
        <TR><TD colspan="2"><input type="submit" value="Show Customer"></TD></TR>
      </TABLE>
    </FORM>
    <H3>Create Customer</H3>
    <FORM action="customer/createCustomer">
      <TABLE>
        <TR>
          <TD>Login:</TD>
          <TD><INPUT type="text" name="login"></TD>
        </TR>
        <TR>
          <TD>Name:</TD>
          <TD><INPUT type="text" name="name"></TD>
        </TR>
        <TR>
          <TD>Email:</TD>
          <TD><INPUT type="text" name="email"></TD>
        </TR>
        <TR>
          <TD colspan=2><INPUT type="submit" value="Create Customer"></TD>
        </TR>
      </TABLE>
    </FORM>
    <H2>Administration</H2>
    <FORM action="admin/admin"><INPUT type="submit" value="Administration Form">
    </FORM>
  </BODY>
</HTML>

The exercise for today's lesson will be to add support for registering applicants to this framework.

One last point to raise for the Agency Web pages is that of using a consistent navigation model for each page. JSP include files are an ideal method for including consistent hyperlinks in each Web page. The following code fragment shows how a standard footer with a navigation button for returning to the home page is included at the end of each Web page, and Listing 13.14 shows the actual footer page.

<%@include file="footer.jsf" %>
</BODY>
</HTML>

Listing 13.14. Full Text of footer.jsf
<HR></HR>
<FORM>
  <INPUT type="button" value="Return to Agency Menu"
         onClick='location="/agency/agency"'>
</FORM>

NOTE

In this case, location is a JavaScript event handler for Button.onclick and has nothing to do with the locations for jobs in the case study. Also, the destination (/agency/agency) should use URL rewriting to maintain the session ID between page accesses; this is covered on Day 14.


If you consider the structure of jobs and applicants in the case study, you will realize that they have two common components:

  • A location that will be a value from an HTML select list

  • A set of skills (possibly) empty that must also be chosen from a list (in this case, an HTML select list that supports multiple options)

Good Java design practice would be to avoid duplicating the code by putting it in a separate method (or helper class) where the functionality can be reused. With JSP design, you can factor out the common code into a separate include file. The following code fragment shows how the JSP code for customer's advertised jobs uses include files:

<TABLE>
  <TR>
    <TD>Description:</TD>
    <TD><input type="text" name="description" value="${job.description}"></TD>
  </TR>
  <TR>
    <TD>Location:</TD>
    <TD>
      <% String location = job.getLocation(); %><%@include file="location.jsf"%>
    </TD>
  </TR>
  <TR>
    <TD>Skills:</TD>
    <TD>
      <% String[] skills = job.getSkills(); %><%@include file="skills.jsf"%>
    </TD>
  </TR>
</TABLE>

Each included file requires a variable to be defined before including the page (location and skills); this is the equivalent of passing a parameter into a method. This is not an ideal solution; in tomorrow's exercise, you will revisit this code and use tag libraries to develop a cleaner solution.

The previous code is part of the advertise.jsp file (see Listing 13.15). This JSP maintains customer details and jobs. It uses two JavaBeans as wrappers around the two Session EJBs called CustomerBean and JobBean. The JobBean wraps around the advertiseJob EJB that uses a compound parameter to identify each job (customer login and job reference). Creating this bean requires careful coding, as shown next. The list of customer jobs must be processed on the Web page in a loop implemented as a Java scriptlet, as shown in the following fragment:

<% String[] jobs = cust.getJobs(); %>
<jsp:useBean id="job" class="web.JobBean" scope="request">
  <jsp:setProperty name="job" property="customer" param="customer"/>
</jsp:useBean>
<% for (int i=0; i<jobs.length; i++) {%>
  <% job.setRef(jobs[i]); %>
  <H3><jsp:getProperty name="job" property="ref"/></H3>
...
<% } %>

Due to the way beans are defined on the page, this code has to be slightly clumsy. The bean is defined once before the Java loop when the customer part of the compound key is defined. Each time round the loop, the bean's setRef() method is called to set the next job reference; this method creates the appropriate advertiseJob Session EJB for use in the body of the loop. An alternative and much better approach is to use a custom tag, as shown on Day 14.

Listing 13.15 shows the entire advertise jobs page. The include files location.jsf and skills.jsf are included on the Web site—not shown here.

Listing 13.15. Full Text of advertise.jsp
<HTML>
  <HEAD><TITLE>Advertise Customer Details</TITLE>
    <%@include file="header.jsf" %>
    <%@page import="java.util.*" %>
    <jsp:useBean id="cust" class="web.CustomerBean" scope="request" >
      <jsp:setProperty name="cust" property="login" param="customer"/>
    </jsp:useBean>
    <H2>Customer details for: <jsp:getProperty name="cust" property="login"/>
    </H2>
    <FORM action="updateCustomer">
      <INPUT type="hidden" name="login" value="<jsp:getProperty
             name="cust" property="login"/>">
      <TABLE>
        <TR><TD>Login:</TD>
           <TD><jsp:getProperty name="cust" property="login"/></TD></TR>
        <TR>
           <TD>Name:</TD>
           <TD><input type="text" name="name" value="<jsp:getProperty
                      name="cust" property="name"/>">
           </TD>
        </TR>
        <TR>
          <TD>Email:</TD>
          <TD><input type="text" name="email" value="<jsp:getProperty
                     name="cust" property="email"/>"></TD>
        </TR>
        <% String[] address = cust.getAddress(); %>
        <TR>
          <TD>Address:</TD>
          <TD><input type="text" name="address" value="<%=address[0]%>"></TD>
        </TR>
        <TR>
           <TD>Address:</TD>
           <TD><input type="text" name="address" value="<%=address[1]%>"></TD>
        </TR>
      </TABLE>
      <INPUT type="submit" value="Update Details">
      <INPUT type="reset">
    </FORM>
    <FORM action="deleteCustomer">
      <input type="hidden" name="customer" value="<%=cust.getName()%>">
      <input type="submit" value="Delete Customer <%=cust.getName()%>"></TD></TR>
    </FORM>
    <H2>Jobs</H2>
    <% String[] jobs = cust.getJobs(); %>
    <jsp:useBean id="job" class="web.JobBean" scope="request">
      <jsp:setProperty name="job" property="customer" param="customer"/>
    </jsp:useBean>
    <% for (int i=0; i<jobs.length; i++) {%>
      <% job.setRef(jobs[i]); %>
      <H3><jsp:getProperty name="job" property="ref"/></H3>
      <FORM action="updateJob">
        <TABLE>
          <TR><TD>Description:</TD>
            <TD><input type="text" name="description" value="<jsp:getProperty
                       name="job" property="description"/>"></TD></TR>
          <TR><TD>Location:</TD>
            <TD><% String location = job.getLocation(); %>
                <%@include file="location.jsf"%>
            </TD>
          </TR>
          <TR><TD>Skills:</TD>
            <TD><% String[] skills = job.getSkills(); %>
                <%@include file="skills.jsf"%>
           </TD>
         </TR>
       </TABLE>
      <INPUT type="hidden" name="customer" value="<jsp:getProperty name="job"
             property="customer"/>">
      <INPUT type="hidden" name="ref" value="<jsp:getProperty
             name="job" property="ref"/>">
      <INPUT type="submit" value="Update Job">
    </FORM>
    <FORM action="deleteJob">
      <INPUT type="hidden" name="customer" value="<jsp:getProperty name="job"
             property="customer"/>">
      <INPUT type="hidden" name="ref" value="<jsp:getProperty name="job"
             property="ref"/>">
      <INPUT type="submit" value='Delete Job <jsp:getProperty name="job"
             property="ref"/>'>
    </FORM>
    <% } %>
    <H2>Create New Job</H2>
    <FORM action="createJob">
    <TABLE>
      <TR>
        <TD>Ref:</TD>
        <TD><INPUT type="text" name="ref"></TD>
      </TR>
      <TR>
        <INPUT type="hidden" name="customer" value="<jsp:getProperty name="cust"
               property="login"/>">
        <TD colspan=2><INPUT type="submit" value="Create Job"></TD>
      </TR>
    </TABLE>
    </FORM>
    <%@include file="footer.jsf" %>
  </BODY>
</HTML>

To complete the customer functionality, the Web interface requires separate pages for

  • Creating a new customer

  • Deleting a customer

  • Updating a customer

  • Creating a new job

  • Deleting a job

  • Updating a job

Rather than reproduce all of these pages, the page for updating a customer is shown in Listing 13.16 (the others can be examined on the Web site). Each page simply creates the appropriate agency, customer, or job bean using the request parameters, and calls the necessary business method.

Listing 13.16. Full Text of updateCustomer.jsp
<HTML>
  <HEAD>
    <TITLE>Update Customer</TITLE>
    <%@include file="header.jsf" %>
    <jsp:useBean id="cust" class="web.CustomerBean" scope="request" >
      <jsp:setProperty name="cust" property="login" param="login"/>
    </jsp:useBean>
    <% cust.updateDetails(request.getParameter("name"), request.getParameter("email")
,request.getParameterValues("address")); %>
    <H3>Updated <jsp:getProperty name="cust" property="login"/> Successfully
    </H3>
    <%@include file="footer.jsf" %>
  </BODY>
</HTML>

Error Page Definition

The last file to examine for the case study is the error page file shown in Listing 13.17.

Listing 13.17. Full Text of errorPage.jsp
<%@ page isErrorPage="true" %>
<%@page import="java.util.*, java.io.* " %>
<HTML>
  <HEAD>
    <TITLE>Agency Error Page</TITLE>
  </HEAD>
  <BODY>
    <H1>Agency Error Page</H1>
    <H2>There has been an error in processing your request.</H2>
    The following information describes the error:
    <H3>Request Parameters</H3>
    <TABLE border="1">
<%
Enumeration params = request.getParameterNames();
while (params.hasMoreElements()) {
  String name = (String)params.nextElement();
  out.println("<TR><TD>"+name+"</TD>");
  String[] values = request.getParameterValues(name);
  for (int i=0; i<values.length; i++) {
    out.println("<TD>"+values[i]+"</TD>");
  }
  out.println("</TR>");
}
%>
    </TABLE>
    <H3>Request Attributes</H3>
    <TABLE border="1">
<%
Enumeration attrs = request.getAttributeNames();
while (attrs.hasMoreElements()) {
  String name = (String)attrs.nextElement();
  out.println("<TR><TD>"+name+"</TD>");
  out.println("<TD>"+request.getAttribute(name)+"</TD>");
  out.println("</TR>");
}
%>
    </TABLE>
    <H3>Session Attributes</H3>
    <TABLE border="1">
<%
Enumeration sess = session.getAttributeNames();
while (sess.hasMoreElements()) {
  String name = (String)sess.nextElement();
  out.println("<TR><TD>"+name+"</TD>");
  out.println("<TD>"+session.getAttribute(name)+"</TD>");
  out.println("</TR>");
}
%>
    </TABLE>
    <H3>Exception</H3>
    <%=exception%>
    <H3>Stack Trace</H3>
<%
StringWriter buf = new StringWriter();
PrintWriter sout = new PrintWriter(buf);
exception.printStackTrace(sout);
out.println(buf.toString());
%>
  </BODY>
</HTML>

This error page is designed for use during development. When an exception occurs, this page displays information about the exception and various Java variables derived from the request, servlet, and page contexts.

At the top of Listing 13.17 is the line

<%@ page isErrorPage="true" %>

This tells the translation phase to include a variable called exception that refers to the exception that caused the page error. This exception is used to display a stack trace on the error page. The first line of the stack trace will identify

  • The name of the generated servlet

  • The line number where the exception occurred

  • The exception that was thrown

  • A brief description of the error

This information can be used to trace back the error to the original JSP file by using the Java code listing for the generated servlet.

For a fully-developed and deployed application, it would be better for the error page to display a user-friendly error message and report the error (perhaps via JavaMail) to an administrator.

The Agency case study error pages are designed to illustrate the principles involved in error reporting and are not necessarily an example of best practice.

Deploying the Case Study JSPs

In today's lesson, you have used a large number of files to create the Web interface to the job agency Session beans. You may find it simpler to use the pre-supplied webagency.war file in the Day13/exercise/j2ee-ri directory on the accompanying Web site or you can build the Web application using deploytool.

Finally, if you prefer, you can use the supplied asant build files to build and deploy the Web Agency example using:

asant build deploy

If you are using deploytool you need to perform the following steps.

1.
Start up deploytool and create a new Web component and add it to a new Web Application file called webagency.war. Set the Web Application name to webagency and the Web context to webagency.

2.
Add the following JSP files from the src/jsp directory to this war file:

  • admin.jsp

  • advertise.jsp

  • agency.css

  • agency.jsp

  • createCustomer.jsp

  • createJob.jsp

  • createLocation.jsp

  • createSkill.jsp

  • deletCustomer.jsp

  • deleteJob.jsp

  • deleteLocation.jsp

  • deleteSkill.jsp

  • errorPage.jsp

  • footer.jsf

  • header.jsf

  • location.jsf

  • modifyLocation.jsp

  • modifySkill.jsp

  • skills.jsf

  • updateCustomer.jsp

  • updateJob.jsp

  • updateLocation.jsp

  • updateSkill.jsp

3.
Add the following class files from the web directory to this WAR file:

  • AgencyBean.class

  • CustomerBean.class

  • JobBean.class

4.
Add the following class files from the agency directory to this WAR file:

  • Advertise.class

  • AdvertiseHome.class

  • AdvertiseJob.class

  • AdvertiseJobHome.class

  • Agency.class

  • AgencyHome.class

  • DuplicateException.class

  • NotFoundException.class

  • Register.class

  • RegisterHome.class

5.
Click Next, select JSP for the EJB component, and then click Next.

6.
Set the JSP Filename to agency.jsp and accept the default Web component name of agency.

7.
Click Finish.

8.
Highlight the agency Web component in the left-hand panel and select the Aliases tab. Add an alias for the agency.jsp of /agency.

9.
Highlight the web application in the left-hand panel and select the EJB Refs tab. Add the EJB references shown in Table 13.5 (they are all Session beans with a remote interface).

Table 13.5. Case Study Web Application EJB References
Coded nameHome i/fRemote i/fPlatform Specific JNDI name
ejb/agencyagency.AgencyHomeagency.Agencyejb/agency
ejb/advertiseagency.AdvertiseHomeagency.Advertiseejb/advertise
ejb/advertiseJobagency.AdvertiseJobHomeagency.AdvertiseJobejb/advertiseJob

10.
Now you will need to create Web components in the same WAR file for every other JSP. You have added all of the required files, so all you need to do is define each one as a JSP page and give it an alias. Table 13.6 lists all the pages you need to add.

Table 13.6. Case Study Web Application JSP Components
JSP FilenameAlias
advertise.jsp/customer/advertise
admin.jsp/admin/admin
createCustomer.jsp/customer/createCustomer
createJob.jsp/customer/createJob
createLocation.jsp/admin/createLocation
createSkill.jsp/admin/createSkill
deletCustomer.jsp/customer/deleteCustomer
deleteJob.jsp/customer/deleteJob
deleteLocation.jsp/admin/deleteLocation
deleteSkill.jsp/admin/deleteSkill
errorPage.jsp/errorPage
updateCustomer.jsp/customer/updateCustomer
updateJob.jsp/customer/updateJob
updateLocation.jsp/admin/updateLocation
updateSkill.jsp/admin/updateSkill

11.
Add agency.jsp as a welcome file and errorPage.jsp as an error page using the File Refs tab, as shown in Figure 13.6

Figure 13.6. Defining Web Application Welcome and Error pages.


12.
Use Tools, Deploy to deploy your application.

If you have not done so already, you must also deploy the Agency application so that the Web interface can communicate with it.

You can access the case study application, with its new Web front end using http://localhost:8000/webagency.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.67.125