# A Personalized Application Example - JSP

A comprehensive example of a user profile is used in the case study of our fictitious training company in Chapter 9,“Developing Custom Tag Libraries.” For this chapter, we will use a basic profile of our users. It will simply contain their favorite product type. Our demonstration is a variation of the shopping-cart application that you have been exposed to in various chapters in this book. Essentially, the shop provides users with the ability to purchase DVDs, CDs, and books from a Web site.The product information comes from a database. No information has been stored about the users in all the previous applications shown.The application has been changed to also maintain user information in a database and allow people to register with the site.

The User Profile

The user profile is shown by the SQL listing in Listing 17.1.This listing is an extract from the database set up script tablesSetUp.sql in the chapter17Personalization.war demonstration site.

Listing Extract from tablesSetUp.sql

create table users (name varchar(50) primary key,
create table interests(
interest varchar(10) not null);
-- now set up some dummy data. This would normally be collected via
-- an HTML form
insert into interests values(‘guest’, ‘CD’);
insert into interests values(‘John’,’DVD’);
insert into interests values(‘Fred’,’book’);
insert into interests values(‘Jane’,’DVD’);
insert into interests values(‘Mel’,’book’);
insert into interests values(‘Mark’,’CD’);
insert into interests values(‘Janet’,’CD’);
create table user_roles (
name varchar(50) not null,
rolename varchar(50) not null,
primary key (name, rolename));
-- add some user and role mappings
insert into user_roles values(‘guest’, ‘none’);
insert into user_roles values(‘John’,’customer’);
insert into user_roles values(‘Fred’,’customer’);
insert into user_roles values(‘Jane’,’customer’);
insert into user_roles values(‘Mel’,’customer’);
insert into user_roles values(‘Mark’,’customer’);
insert into user_roles values(‘Janet’,’customer’);

The table called interests in Listing 17.1 is used to contain the users’ core interest, which as you can see is CD, DVD, or book. It could be a great deal more complex, storing all sorts of information about the user, but for this example, we’ll keep it simple.The usernames and passwords are stored in another table called users.

Setting Up Login Using the Database

When the provision of usernames and passwords was discussed in Chapter 16,“Security and JSP,” the usernames and passwords were maintained in the tomcat-users.xml file. This was because we were not adding or modifying user information.We are now using a database because you are storing more than just the usernames and passwords, and you also want to be able to dynamically add users as they register. To configure Tomcat to use your database to contain user information, you will need to add the following entry to server.xml:

<Realm className=”org.apache.catalina.realm.JDBCRealm” debug=”99”
driverName=”org.gjt.mm.mysql.Driver”
connectionURL=”jdbc:mysql://localhost:3306/jsphandbook?user=root”
userRoleTable=”user_roles” roleNameCol=”rolename” />
You will then need to locate and comment out the following entry:
<Realm className=”org.apache.catalina.realm.MemoryRealm”/>

This is how Tomcat was specifying to use tomcat-users.xml to contain user information.

If you notice from the additional entry in server.xml, there is a reference to the users table and also a reference to a user_role table.This table maps users to roles, as did the tomcat-users.xml discussed in Chapter 16.We have used a single role called customer, and the SQL for that table is also shown in Listing 17.1.

We need a login page to enable users to log in, and we need a registration form to enable users to register.This is shown in Figure with its code shown in Listing 17.2.

<title>
Welcome to Ashdown.com - The best deals for Books, CDs and DVDs!
</title>
<body bgcolor=”#FFCC99”>
<form method=”POST” action=”j_security_check”>
<input type=”submit” value=”Continue”>
</form>
<hr>
<form method=”post” action=”registerServlet”>
<br>Once you submit this form, you will be redirected to this page. <br>
<input type=”submit”>
</form>
</body>
</html>

You will also know that there must be an entry in the web.xml file. Basically, all the shopping pages are in a folder called shopping, and it is this folder that is being protected by the form-based login. Listing below shows web.xml for our application.Various aspects of this will be referred to as we progress.

Listing web.xml

<?xml version=”1.0” encoding=”ISO-8859-1”?>
<web-app xmlns=”http://java.sun.com/xml/ns/j2ee”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd” version=”2.4”>
<servlet>
<servlet-name>
controller
</servlet-name>
<servlet-class>
com.conygre.ShoppingCartController
</servlet-class>
</servlet>
<servlet>
<servlet-name>
registerServlet
</servlet-name>
<servlet-class>
com.conygre.RegistrationServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
controller
</servlet-name>
<url-pattern>
/shopping/welcome
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
registerServlet
</servlet-name>
<url-pattern>
/registerServlet
</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/welcome</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>http://java.sun.com/jstl-el/core</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jstl-el/sql</taglib-uri>
<taglib-location>/WEB-INF/sql.tld</taglib-location>
</taglib>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/shopping/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>guest</role-name>
<role-name>customer</role-name>
</auth-constraint>
</security-constraint>
<auth-method>FORM</auth-method>
</web-app>

Note the security aspects toward the bottom of Listing .The <securityconstraint> element and the <login-config> elements are specifying both the login form and also the fact that anything within the shopping subfolder is protected. It is this folder that contains our shopping Web site.

The Profile Object

For the application to access user information in a convenient way, an object used to encapsulate the user information will be used.This is set up for us with the help of a servlet and a Profile bean.The controller servlet acts as the gateway into the Web application after people have logged in.The controller servlet source code is shown in Listing below.

Listing ShoppingCartController.java

// this servlet is used as the entry point into the application
// it sets up the profile object and the shopping cart for the current user
// it then finally forwards to the home page of the application, welcome.jsp
package com.conygre;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ShoppingCartController extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doPost(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
HttpSession session = req.getSession();
ServletContext application = getServletContext();
// if there is no profile object set up to represent the current user
if (session.getAttribute(“currentUser”) == null){
// create a new profile object, passing in the username
Profile profile = new Profile(req.getRemoteUser());
session.setAttribute(“currentUser”, profile);
// create a shopping cart for them as well!
session.setAttribute(“cart”, new com.conygre.Cart());
}
RequestDispatcher rd =
application.getRequestDispatcher(“/shopping/welcome.jsp”);
rd.forward(req, res);
}
}

The controller servlet has two main functions. It sets up the shopping cart. and it also creates something that we have called the profile object, which represents the current user.The profile object used here is a very basic object in terms of its properties. It contains the username and the preferred product type, which are represented by the two properties, name and interest.The issue to consider is this; how does it know what the interest value should be? The value is within the database, and it needs to be looked up from there.The code is shown in Listing below.

Listing Profile.java

// this class represents the current user
// the user name is passed in to the constructor
// the other profile attribute for the interest is
// obtained from the database
package com.conygre;
import java.sql.*;
public class Profile {
private String name;
private String interest;
public Profile(String name) {
this.name = name;
// now extract the interest from the database
Connection conn = null;
ResultSet result = null;
Statement stmt = null;
try {
Class c = Class.forName(“org.gjt.mm.mysql.Driver”);
}
catch (Exception e) {
System.out.println(“Error occurred “ + e);
}
try {
conn = DriverManager.getConnection
(“jdbc:mysql://localhost:3306/jsphandbook”, “root”, “”);
}
catch (SQLException e) {
System.out.println(“Error occurred “ + e);
}
try {
stmt = conn.createStatement();
result = stmt.executeQuery
(“SELECT * FROM interests where username=”” + name + “””);
// move the cursor to the first and only row
result.next();
// set the interest variable
interest = result.getString(“interest”);
// close the connection
conn.close();
}
catch (SQLException e) {
System.out.println(“Error occurred “ + e);
}
}
public String getName(){
return name;
}
public void setName(String s){
name = s;
}
public String getInterest(){
return interest;
}
public void setInterest(String s){
interest = s;
}
}

Then the profile object is created, the database is accessed and the interest value is obtained. Clearly, there could be many more profile properties. Note that the database access code is within the bean.This could be moved out and placed in a separate bean, but we left it in for simplicity so you could clearly see exactly what is going on.

Personalizing Pages

This profile bean was created in the controller servlet, and then placed into a sessionscoped attribute called currentUser.This means that the pages now have convenient access to this data.The welcome page, welcome.jsp, uses this data for personalization. Figure shows what welcome.jsp looks like when viewed in a browser, logged in as the user called Mel.This user has books as his preferred product type. Notice the circled part of the page.

The circled part of the diagram is personalized to the user based on his preferences. Figure shows exactly the same the page, but for a different user. Both users get different content presented.The source code for welcome.jsp.

welcome.jsp as seen by user Mel.

welcome.jsp as seen by a user Mark.

Listing welcome.jsp

<%@ taglib uri=”http://java.sun.com/jstl-el/core” prefix=”c” %>
<%@ taglib uri=”http://java.sun.com/jstl-el/sql” prefix=”sql” %>
<jsp:include page=”cache.jsp”/>
<sql:setDataSource var=”handbookDb”
user=”root”
url=”jdbc:mysql://localhost:3306/jsphandbook”
driver=”org.gjt.mm.mysql.Driver”
scope=”application”
/>
<jsp:useBean id=”stock” class=”com.conygre.Stock” scope=”application”/>
<html>
<title>Welcome to Ashdown.com –
The best deals for Books, CDs and DVDs!</title>
<body bgcolor=”#FFCC99”>
At the moment we have many very exiting items for sale
at amazing prices.
we would want to draw
<br> your attention to the following item.<p>
<font color=”blue”>
<%-- this content will vary depending upon the user --%>
<c:if test=”${currentUser.interest == ‘book’}”> <p>The book<br> <input type=”checkbox” name=”id” value=”<c:out value=’${stock.books[0].id}’/>”>
<c:out value=”${stock.books[0].title}” /> - <c:out value=”${stock.books[0].author}” /> @
<c:out value=”${stock.books[0].price}” /> </c:if> <c:if test=”${currentUser.interest == ‘DVD’}”>
<p>The DVD<br>
<input type=”checkbox” name=”id”
value=”<c:out value=’${stock.dvds[0].id}’/>”> <c:out value=”${stock.dvds[0].title}” /> -
<c:out value=”${stock.dvds[0].director}” /> @ <c:out value=”${stock.dvds[0].price}” />
</c:if>
<c:if test=”${currentUser.interest == ‘CD’}”> <p>The CD<br> <input type=”checkbox” name=”id” value=”<c:out value=’${stock.cds[0].id}’/>”>
<c:out value=”${stock.cds[0].title}” /> - <c:out value=”${stock.cds[0].artist}” /> @
<c:out value=”\${stock.cds[0].price}” />
</c:if>
</form>
</body>
</html>

The most important part of this listing is the last section. It is querying the currentUser.interest property.Which if block gets output is dependent on the value of the currentUser.interest property. Mark preferred CDs and was presented with information about a CD, whereas Mel preferred books and was presented with a book.

User Registration

Finally, we need to look at how users register with the Web site in the first place.The users that we have been working with were already set up.

Listing 1RegistrationServlet.java

// this servlet is used for the registration of new users
// it is where the registration form in login.html submits
// its data
package com.conygre;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
public class RegistrationServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// set up a connection
Connection conn = null;
ResultSet result = null;
PreparedStatement stmt = null;
PreparedStatement stmt2 = null;
PreparedStatement stmt3 = null;
try {
Class c = Class.forName(“org.gjt.mm.mysql.Driver”);
}
catch (Exception e) {
System.out.println(“Error occurred “ + e);
}
try {
conn = DriverManager.getConnection
(“jdbc:mysql://localhost:3306/jsphandbook”, “root”, “”);
}
catch (SQLException e) {
System.out.println(“Error occurred “ + e);
}
// create a prepared statement to create a new user
// and set up their interests
try {
stmt = conn.prepareStatement
(“INSERT into interests (username, interest) values (?,?)”);
stmt.setString(1, req.getParameter(“name”));
stmt.setString(2, req.getParameter(“interest”));
stmt.executeUpdate();
stmt2 = conn.prepareStatement
(“INSERT into users (name, password) values (?,?)”);
stmt2.setString(1, req.getParameter(“name”));
stmt2.executeUpdate();
stmt3 = conn.prepareStatement
(“INSERT into user_roles (name, rolename) values (?,?)”);
stmt3.setString(1, req.getParameter(“name”));
stmt3.setString(2, “customer”);
stmt3.executeUpdate();
// close the connection
conn.close();
}
catch (SQLException e) {
System.out.println(“Error occurred “ + e);
}
// now redirect to the welcome servlet,
// because it is in the protected folder
res.sendRedirect(“shopping/welcome”);
}
}

Notice that a number of prepared statements are used in this registration servlet to update the database with the new entries.Three tables are modified—the user table, the interests table, and the user_roles table. Note that there is no error checking in this servlet. It has been left out for clarity. A diagrammatic representation of our personalization can be seen in Figure.

Rules-based personalization.

Essentially, the page uses rules to decide which content to show based on the user information provided.