Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E.

.pdf
Скачиваний:
45
Добавлен:
24.05.2014
Размер:
6 Мб
Скачать
☆

C H A P T E R15

J2EE in the Real World: Combining Servlets with Enterprise JavaBeans

n this chapter, you will learn how to tie Java servlets to Enterprise JavaBeans. IWe’ll illustrate these concepts by adding a servlet layer to the e-commerce EJB

system we’ve been developing.

By reading this chapter, you’ll see how servlets work, how to partition the servlets into manageable entities, how to tie servlets to enterprise beans, and how to control transactions from servlets. Additionally, we’ll look at how to optimize and tune our e-commerce deployment, and we will discuss EJB design strategies.

The Role of Servlets in an EJB Deployment

In the Web-based world, Sun Microsystems promotes two choices for rendering a user interface to browser-based clients: Java applets or thin Java Server Pages / servlets. Applets are interesting because they can be fully functional Java programs (assuming you digitally sign them). Due to their download time, however, large applets are starting to die off in favor of a thin-client scenario. Some applet enthusiasts may argue that HTML does not give the breadth of GUI features needed in a complex interface. But with the advent of DHTML, XML, and other thin-client advances, the GUI functionality of thin clients begins to look very appealing. This is especially true for a business application such as our e- commerce deployment—we shouldn’t need anything more than what the flavors of HTML can provide.

There are other benefits of thin-client deployments as well. In a thick-client scenario, RMI’s JRMP or IIOP (see Chapter 11) is the transport protocol used.

451

Go back to the first page for a quick link to buy this book online!

452 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

In a corporate firewall environment, these transports need to tunnel through firewalls to facilitate client/server communication (firewall tunneling is briefly mentioned in Appendix A). Unfortunately, firewall tunneling is very slow because you’re performing remote procedure calls over HTTP, a protocol that requires a new connection to be made on every data transfer. Thus, although JRMP and IIOP both tunnel through firewalls, they are inefficient for serious use.

To facilitate a Web-based user interface, we have chosen to use servlets in our deployment. Servlets are networked modules that run within a request/responseoriented server. A request is a call from a client, perhaps remotely located. Requests contain data that the client wants to send to the server. A response is data that the server wants to return to the client to answer the request. A servlet is a Java object that takes a request as input, parses its data, performs some logic, and then issues a response to the client.

Servlets, on the other hand, serve as an HTTP-aware middle layer that resides on the server side. They know how to communicate with both the client, in HTTP, and your enterprise beans, via RMI or IIOP. This makes servlets the ideal technology for Web-based GUI development.

Alternatives to Servlets

There are other mechanisms for Web-based communications as well. For example, both Microsoft’s Active Server Pages (ASP) and Sun’s Java Server Pages (JSP) provide a script-like environment for performing GUI operations. (JSP is designed as a cross-platform solution; ASP is not, although there are cross-platform implementations that are unsupported by Microsoft.) What advantages do these technologies have over servlets?

To answer this question, let’s take a deeper look at how servlets work. Servlets are compiled Java classes—they are not script. When a servlet wants to write HTML back to the client, it must make a method call, such as:

response.write("<B>Hi there</B>");

In ASP or JSP, you’d put the HTML directly into the script file itself:

<B>Hi there</B>

With servlets, you have the annoyance of having to code in a response.write() whenever you want to send some UI text to the client. With JSP, you simply write the UI directly into the script; however, with JSP, you need to perform extra dancing steps to do any Java operations. Thus, ASP and JSP are very well suited for look-and-feel-centric applications that rely heavily on GUI work, whereas servlets are well suited for logic-centric applications. That is, if your servlet’s

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Combining Servlets with Enterprise JavaBeans 453

primary purpose is to dump a UI to the client, it’s better modeled as JSP, whereas if your servlet performs computations or other overhead, it’s best left as a servlet. In reality, JSP script pages are compiled into a Java servlet and then executed, so you’re really dealing with the same underlying technology in either scenario.

The great thing about externalizing look-and-feel into JSP is that a Web designer can later modify the script’s look and feel without knowing how to write or compile Java programs. This is great for an IT department, and it allows end users to easily customize the flavor of their Web sites. This effectively reduces the maintenance cost of your Web pages.

In the end, most deployments will have a combination of both servlets and JSP:

The logic part of your application should be in servlets or in a combination of servlets and JavaBeans. Note that these are regular JavaBeans—not Enterprise JavaBeans (we touch on the differences between JavaBeans and Enterprise JavaBeans in Chapter 1). You can use JavaBeans as a cache for your Enterprise JavaBeans, reducing network round trips.

The look-and-feel part of your application should be externalized into JSP to allow the end user to easily change it. Your JSP could call into the servlets or JavaBeans for performing logic operations.

Unfortunately, JSP currently cannot talk to Enterprise Beans, only to JavaBeans and servlets. Sun Microsystems is promising that the new version of JSP will correct this. For our deployment, we’ll stick with straight Java servlets.

Implementing Our Servlets

In Chapter 12, we first designed our servlet architecture. We design a total of seven different servlets composing our presentation tier:

A Login servlet for handling user login

A Web Storefront servlet for presenting the initial main page

ThinClient Resources

Lots of data is already available on servlets. Rather than repeat what’s already been said, we’ll concentrate on how our e-commerce servlets are used in an EJB environment. We’ll assume that you understand servlet basics. If you’re new to this arena, check out the book’s accompanying Web site, where we list links to several resources on learning Java servlets. From here on, we’ll assume you already have a grasp on servlet basics.

Go back to the first page for a quick link to buy this book online!

454 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

A Catalog servlet for browsing the available products

A Product Base servlet for containing all the available products

A Product Detail servlet for displaying the specifics of a particular product

A Quote View servlet for final quantity modifications before ordering the products

A Purchasing servlet for completing the transaction when an order has been generated

Let’s take a look at the servlets in more detail.

The Login Servlet

The login servlet will be the first servlet the user deals with when going to Jasmine’s Web site. It’s responsible for reading in the user’s name and password, then retrieving the Customer entity bean that matches that name.

If the passwords match, a new Quote stateful session bean is started on behalf of this customer. The customer information is stored in the Quote so that the quote will be associated with a specific customer—used for billing and shipping information. As the user navigates the store, the Quote will serve as a cache that the user can add products to and remove products from.

If the passwords don’t match, an error is displayed and the user is given another chance to enter his or her information.

We’ll perform all the authentication through querying the fields on existing customer entity beans. This is a fairly secure means of authentication. If we’re worried that someone will intercept the client’s password over the Internet, we could impose encryption via the Secure Socket Layer (SSL) when sending the password over HTTP.

Let’s take a look at the implementation. It resides in LoginServlet.java, shown in Source 15.1.

There are three important methods in our Login servlet: init(), doGet(), and writeForm().

init() is called automatically by the underlying servlet engine when it kicks our servlet into memory. init() is called only once, and it performs one-time initialization that is not client-specific. In our init(), we perform JNDI initialization and use JNDI to look up a couple of home objects. We store these home objects in local variables, so we can use them over and over again when any client connects and calls our doGet() method.

doGet() is responsible for processing page hits from users. If the user is connecting for the first time (i.e., if there are no form results coming back to us),

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Combining Servlets with Enterprise JavaBeans 455

package com.wiley.compBooks.ecommerce;

import java.io.*; import java.util.*; import javax.servlet.*;

import javax.servlet.http.*; import javax.naming.*;

/**

*This is the very first servlet the client deals with.

*It's a Login authentication servlet. It asks the user

*for his or her name and password, and it verifies that data

*against the Customer entity beans stored in a database.

*If the user authenticates properly, a new Quote is saved

*in his or her HttpSession object, and the user can begin to add

*items to the quote and shop around.

*/

public class LoginServlet extends HttpServlet {

/*

* Customer home object for authenticating user */

private CustomerHome customerHome;

/*

*Quote home object for creating a new quote when

*the user logs in.

*/

private QuoteHome quoteHome;

/**

*The servlet engine calls this method once to

*initialize a servlet instance.

*

*In the body of this method, we acquire all the

*EJB home objects we'll need later.

*/

public void init(ServletConfig config) throws ServletException {

super.init(config);

try { /*

*Get the JNDI initialization parameters.

*We externalize these settings to the

*servlet properties file to allow end

*users to dynamically reconfigure their

*environment without recompilation.

*/

Source 15.1 LoginServlet.java (continues).

Go back to the first page for a quick link to buy this book online!

456 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

String initCtxFactory = getInitParameter(Context.INITIAL_CONTEXT_FACTORY);

String providerURL = getInitParameter(Context.PROVIDER_URL);

/*

*Add the JNDI init parameters to a

*properties object.

*/

Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, initCtxFactory); env.put(Context.PROVIDER_URL, providerURL);

/*

*Get the initial JNDI context using the above

*startup params.

*/

Context ctx = new InitialContext(env);

/*

* Look up the Home Objects we need via JNDI */

customerHome = (CustomerHome) ctx.lookup("Ecommerce.CustomerHome"); quoteHome = (QuoteHome) ctx.lookup("Ecommerce.QuoteHome");

}

catch (Exception e) { log(e);

throw new ServletException(e.toString());

}

}

/**

*Writes the Login Screen (private use only)

*@param showError true means show an error b/c client

*was not authenticated last time.

*/

private void writeForm(HttpServletResponse response, boolean showError) throws IOException {

/*

*Now, we write the response. Set content-type

*header, indicating that we will be writing in

*HTML.

*/

response.setContentType("text/html"); PrintWriter out = response.getWriter();

out.println( "<html>" +

"<head><title> Computer Login </title></head>" +

Source 15.1 LoginServlet.java (continues).

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Combining Servlets with Enterprise JavaBeans 457

"<body bgcolor=\"#ffffff\">" + "<center>" +

"<hr> <br>  " + "<h1>" +

"<font size=\"+3\" color=\"red\">Jasmine's </font>" + "<font size=\"+3\" color=\"purple\">Computer </font>" + "<font size=\"+3\" color=\"green\">Parts</font>" + "</h1>" +

"</center>" +

"<br>   <hr> <br>  ");

/*

* Print out the total and the form for the user. */

out.println(

"<p>Please Login<p>" +

"<form action=\"" + response.encodeUrl("/servlet/login") + "\" method=\"get\">" +

"<table>" + "<tr>" +

"<td><strong>Name:</strong></td>" + "<td><input type=\"text\" name=\"Login\"" + "value=\"Ed Roman\" size=\"19\"></td>" + "</tr>" +

"<tr>" + "<td><strong>Password:</strong></td>" + "<td>" +

"<input type=\"text\" name=\"Password\" " + "value=\"password\" size=\"19\"></td>" + "</tr>" +

"<tr>" + "<td></td>" +

"<td><input type=\"submit\"" + "value=\"Submit Information\"></td>" + "</tr>" +

"</table>" + "</form>");

if (showError == true) { out.println(

"<p><strong>Could not log in!" +

" Please try again.</strong><p>");

}

Source 15.1 LoginServlet.java (continues).

Go back to the first page for a quick link to buy this book online!

458 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

out.println("</body></html>");

out.close();

}

/**

*The servlet engine calls this method when the user's

*desktop browser sends an HTTP GET request.

*/

public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

/*

* Set up the user's HttpSession */

HttpSession session = request.getSession(true);

/*

*Retrieve the login name / password from the

*URL string.

*/

String loginName = request.getParameter("Login");

String password = request.getParameter("Password");

/*

*If user has not tried to log in yet, present

*him with the login screen.

*/

if ( (loginName == null) || (password == null) ) { writeForm(response, false);

}

/*

*Otherwise, the user has been to this screen

*already and has entered some information.

*Verify that information.

*/ else {

/*

*Find all Customer Entity Beans which

*match the loginname

*/

Enumeration customers = null; try {

customers = customerHome.findByName(loginName);

}

catch (Exception e) { log(e);

throw new ServletException(e.toString());

}

Source 15.1 LoginServlet.java (continues).

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Combining Servlets with Enterprise JavaBeans 459

/*

*For each customer, check if the passwords

*match.

*/

while (customers.hasMoreElements()) {

Customer c = (Customer) customers.nextElement();

/*

*Do a little sanity check to make

*sure the customer has a password.

*/

String verifiedPassword = c.getPassword(); if (verifiedPassword == null) {

System.err.println("Error: Customer " + c.getName() + " does not have a password registered.");

break;

}

/*

*If the passwords match, make a new

*Quote session bean and add it to

*the user's HttpSession object. When

*the user navigates to other servlets,

*the other servlets can access the

*HttpSession to get the user's Quote.

*/

if (verifiedPassword.equals(password)) { try {

Quote quote = quoteHome.create(c); session.putValue("quote", quote);

/*

* Call the welcome screen servlet */

response.sendRedirect(response.encodeUrl("/servlet/wsf"));

return;

}

catch (ClassCastException e) { log(e);

throw new ServletException(e.toString());

}

catch (Exception e) { log(e);

throw new ServletException(e.toString());

}

}

}

Source 15.1 LoginServlet.java (continues).

Go back to the first page for a quick link to buy this book online!

460 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

/*

*If there was no match, the user is

*not authenticated. Present another

*login screen to the user, with an error

*message indicating that he or she is not

*authenticated.

*/

writeForm(response, true);

}

}

private void log(Exception e) { getServletConfig().getServletContext().log(e, "");

}

public String getServletInfo() {

return "The Login servlet verifies a user.";

}

}

Source 15.1 LoginServlet.java (continued).

we simply print the form out. This is what the writeForm() method does. The writeForm() method prints out some HTML to the client, along with a couple of input tags. The input tags will look like text input boxes to the end user, as shown in Figure 15.1.

When the user enters data into the input boxes and submits them, our doGet() method will be called again, only this time, we’ll have a username and password parameter passed back to us from the client. We extract the parameters from the request and then perform an EJB find() on the Customer home object, which we saved from init(). The finder method will return all Customers whose names match the input text. We then query the password on each of the returned EJB objects. If the passwords match, the user is authenticated. Otherwise, we print out the form again, only this time indicating an error message as well.

If the client is authenticated, we use the Quote home object to create a new Quote EJB object for this user. We then store the Quote in the user’s servlet session. This is a per-client presentation tier stateful cache that we can exploit to store the current Quote. When the user connects again later, no matter which servlet he or she hits, we can extract the current Quote from the servlet session. Thus, all of our servlets will be nonclient-specific, being able to service any client. They’ll figure out which client browser is connecting to the Web server by querying the Quote stateful session bean, stored in the servlet session.

Go back to the first page for a quick link to buy this book online!