Bean Persistence

I l @ ve RuBoard

Now that you have this simple Bean, you can start to play with it using JSP. JSP uses a persistence model that lets you maintain a Java object for the scope of the current page, the current request, the current user session, or the entire time that the server is running. These four types of persistence are referred to as page scope, request scope, session scope, and application scope.

  • An object with page scope is available during the evaluation of this JSP only. This means that if the request is forwarded to another page in the same application, the object will not be preserved.

  • An object stored with request scope is available during the entire processing of the current request from a client. This object will be preserved if the request is forwarded to another page.

  • Session-scoped objects are associated with a user session, which is created when a user first encounters the server and persists until it is explicitly destroyed or the session times out. Objects with session scope can be accessed at any point during the session.

  • Application-scoped objects are available to any page of any user session, for the life of the application. They are akin to global variables .

HOW DOES JSP MAKE PERSISTENCE WORK?

Web requests are theoretically stateless. All that a Web server knows about an incoming request is the IP address of the requester (which actually might be a proxy server), the URL, perhaps some posted data, and miscellaneous information about the client browser. So how does JSP maintain the illusion of a persistent session across multiple requests?

As you might already know, the answer is cookies. Two types of cookies exist in the world, the "evil" ones that stay around forever (or some long period of time) and those that identify you or things about you to a Web server during a single browser session. These cookies use the expire=date feature of the HTTP cookie specification. However, if you don't specify an expiration date, the cookie automatically disappears as soon as the user closes the browser.

These more benign cookies are ideal for uniquely identifying a user session while someone is visiting your Web site. JSP automatically assigns you a temporary cookie when you first come to the site and then uses it to keep your objects associated with you.

This can lead to an interesting problem seen mainly in testing. If you have two browser windows open , one for testing and one looking at the admin interface, for example, you can end up changing your session ID by logging in on the second window, which can make the first one "lose track" of where it is because it loses all of its associated session data.

Because of the paranoia over cookies, some users turn them off altogether. In that case, JSP uses URL rewriting, which means placing a parameter in all the links and form submits from a Web page that identifies the session. This leads to URLs like:

http://www.mysite.com/hithere.jsp?sessionid=345234523454325565

A big problem with URL rewriting is that if the user bookmarks the page, it will include the session ID in the bookmark, which can lead to later confusion for the Web server if the user tries to return to the page.

Permanent cookies can also be very useful in Web design. We'll talk about them and why they aren't as terrible as some make them out to be in Chapter 8, "Retrieving, Storing, and Verifying User Input."

Using useBean

Listings 2.2 and 2.3 show a pair of pages that use a Bean to pass data from one to the other inside the same session.

Listing 2.2 handoff1.jsp
 <jsp:useBean id="handoff" scope="session" class="com.cartapp.user.User" /> <HTML> <BODY> This is the setting page! <%     handoff.setFirstName("George"); %> </BODY> </HTML> 
Listing 2.3 handoff2.jsp
 <jsp:useBean id="handoff" scope="session" class="com.cartapp.user.User" /> <HTML> <BODY> <H1>This is the getting page!<br>handoff= <%= handoff.getFirstName() %></H1> </BODY> </HTML> 

If you request handoff1.jsp and then handoff2.jsp, you'll get the Web page shown in Figure 2.1.

Figure 2.1. Handing off a value between Web pages.

graphics/02fig01.gif

The most interesting thing to look at here is the useBean tag at the top of the files. This tag tells JSP to persist a Bean with the ID specified for the scope requested ”in this case, one named handoff ”for the life of the session.

When a Bean has been instantiated with a given ID, any other page that requests that ID, as long as it's inside the specified scope, will get the same object. This allows the JSP application to carry a set of objects as it processes requests associated with the same user, for example.

ONE NAME , MULTIPLE CLASS, JSP GO BOOM!

One of the more irritating bugs to track down in JSP can occur if you inadvertently use the same ID name with two different classes. To understand why this breaks JSP, let's look at some code snippets and the underlying Java that they produce. Listing 2.4 shows a slightly different version of handoff2.jsp.

Listing 2.4 handoff_broke.jsp
 <jsp:useBean id="handoff" scope="session" class="com.cartapp. graphics/ccc.gif user.DifferentUser" /> <HTML> <BODY> <H1>This is the getting page!<br>handoff= <%= handoff.getFirstName() %></H1> </BODY> </HTML> 

DifferentUser is just a copy of the User class under a different name. When you request handoff_broke.jsp from Tomcat (after running handoff1.jsp), you get the error page shown in Figure 2.2.

Figure 2.2. A broken handoff.

graphics/02fig02.gif

Here's why: The useBean tag in handoff1.jsp turns into this Java:

 com.cartapp.user.User handoff = null; boolean _jspx_specialhandoff  = false;  synchronized (session) {    handoff= (com.cartapp.user.User)               pageContext.getAttribute("handoff",PageContext. graphics/ccc.gif SESSION_SCOPE);    if ( handoff == null ) {       _jspx_specialhandoff = true;        try {           handoff = (com.cartapp.user.User)                      java.beans.Beans.instantiate(this.getClass( graphics/ccc.gif ).getClassLoader(),                                 "com.cartapp.user.User"); 

In contrast, handoff_broke.jsp has the following:

 com.cartapp.user.DifferentUser handoff = null; boolean _jspx_specialhandoff = false;  synchronized (session) {    handoff= (com.cartapp.user.DifferentUser)               pageContext.getAttribute("handoff",PageContext. graphics/ccc.gif SESSION_SCOPE);    if ( handoff == null ) {       _jspx_specialhandoff = true;        try {           handoff = (com.cartapp.user.DifferentUser)                      java.beans.Beans.instantiate(this.getClass( graphics/ccc.gif ).getClassLoader(),                                 "com.cartapp.user. graphics/ccc.gif DifferentUser"); 

When handoff_broke.jsp is run, it calls pageContext.getAttribute to get the object called handoff . It then tries to cast it to the DifferentUser class. Unfortunately, when handoff1 is run, it creates an object of type User ; when the cast tries to coerce it to DifferentUser , it fails.

Thus, it's very important to keep your persistent object names straight and not to use the same name for objects of two different types.

The setProperty Tag

Along with the useBean tag, other JSP tags talk to Java Beans. The most useful is the jsp:setProperty tag. It allows you to fill in a Bean's values from form data coming in from a submit.

Here's a demonstration of how setProperty can work. First, let's add a simple validation to User.java :

 public boolean isValidUserData() {  return ((firstName != null) && (firstName.length() > 0) &&          (lastName != null) && (lastName.length() > 0)); } 

Now let's create a new user form (see Listing 2.4) and a handler page for the form (see Listing 2.5).

Listing 2.4 new_user_form.jsp
 <jsp:useBean id="user" scope="session" class="com.cartapp.user.User" /> <BODY> <H1>Enter New User Data</H1> <FORM ACTION="create_user.jsp" METHOD="POST"> Last Name: <INPUT TYPE="TEXT" NAME="lastName"><BR> First Name: <INPUT TYPE="TEXT" NAME="firstName"><BR> <INPUT TYPE="SUBMIT"> </FORM> </BODY> 
Listing 2.5 create_user.jsp
 <jsp:useBean id="user" scope="session" class="com.cartapp.user.User" /> <jsp:setProperty name="user" property="*" /> <BODY> <H1>Validating New User Data</H1> <%     if (user.isValidUserData()) { %> <H2>User Data Validated</H2> <% }  else { %> <H2>Missing Either Last or First Name</H2>      <% }  %> </BODY> 

You should stop and restart Tomcat to make sure that you get the new version of the class file.

When you submit the form with no data in the fields, you get the screen shown in Figure 2.3.

Figure 2.3. Missing data.

graphics/02fig03.gif

In comparison, when both fields are filled out correctly, you get the screen shown in Figure 2.4.

Figure 2.4. Everything is there.

graphics/02fig04.gif

Later in the book, we'll look at form validation in much more detail. For the moment, let's concentrate on what the setProperty tag does.

For every form field that is handed to the JSP page in the request, JSP checks to see if the setProperty tag is specifying a Bean with an equivalent property. For example, there's a field called lastName in the form, and a setLastName accessor in the user Bean. JSP tries to coerce the data in the field into the type of the accessor's argument, and then call the accessor to set the property.

WHO GETS THE DATA?

Let's suppose that you have two user objects instantiated under different IDs (which is perfectly legal). Let's further suppose that you use a setProperty tag on both of them. Which one will get the data from the form submit?

The answer is, both. As each setProperty is encountered , it runs over the same list of request variables from the form and tries to find matches in the Bean specified. This means that you need to be careful when setting several Beans from one form. For example, if you are setting the credit card and user data from a single form, and both credit card and user have a property called name, both setName methods will be called if there is a name field in the form and you use setProperty with the * option. To avoid this problem, you can use setProperty with an explicit third argument stating which property you want to set. However, this can get cumbersome when you have several dozen properties to set. A better solution is to use userName and creditCardName as property names instead so that they are unique.

Getting Beans to See Each Other

Sooner or later, you're going to want to let two Beans see each other. For example, if you have a globally persistent phone directory object and a session-persistent user object, you might want the user object to be capable of referencing the phone directory object.

 <jsp:useBean id="user" scope="session" class="com.cartapp.user.User" /> <jsp:useBean id="directory" scope="application" class="com.cartapp.directory.Directory" /> <BODY> <H1>My Phone Number</H1> My phone number is <%= user.getMyPhoneNumber(directory) %> </BODY> 

Of course, you could also write it as follows :

 My phone number is <%= directory.getUserPhoneNumber(user) %> 

This works a lot of the time, especially if you need to reference the other object only once, but it doesn't work in all cases. Consider the following code:

 <jsp:useBean id="user" scope="session" class="com.cartapp.user.User" /> <jsp:useBean id="directory" scope="application" class="com.cartapp.directory.Directory" /> <jsp:setProperty name="user" property="*" /> 

Let's further suppose that the form that calls this JSP page has a field called phoneNumber , and you want to validate the phone number against the phone directory. In the setPhoneNumber method of user , you need a handle on the directory object. In this case, there's no way to hand it in via an argument. Here's one workaround:

 <jsp:useBean id="user" scope="session" class="com.cartapp.user.User" /> <jsp:useBean id="directory" scope="application" class="com.cartapp.directory.Directory" /> <% user.setSystemDirectory(directory); %> <jsp:setProperty name="user" property="*" /> 

You need to provide a new property on the user object called systemDirectory of type com.cartapp.directory.Directory , which gets set right before you do the setProperty . Then the setPhoneNumber method can use the local object's reference to the directory object.

A final way to get access is to access it in the Bean via the request object, which we'll talk about in Chapter 3, "Using Servlet Functionality with JSP."

I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net