views:

239

answers:

2

Hello everyone, I would like to ask you some help in clarifying a few issues. But, before anything, some code is inbound first - it's a really simple login example I've constructed.

Container is Tomcat 5.5.27.

Let's assume correct username and pass combination is entered; questions are at the bottom.

LoginPage.jsp (entrypoint - view)

<%@ page language="java" contentType="text/html; charset=windows-1250" pageEncoding="windows-1250"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html>
 <head>
  <link rel="stylesheet" type="text/css" href="mystyle.css" />
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Login Page</title>
 </head>
 <body>
  <div id="page">
   <div id="content_container">
    <div id="content">
     <form action="LoginServlet">
     Username: <input type="text" name="username"><br>
     Password: <input type="text" name="password"><br>
     <input type="submit" value="Submit">
     </form>
    </div>
   </div>
  </div>
 </body>
</html>

LoginServlet.java (controller)

public class LoginServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

public LoginServlet() {
  super();
}

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  try {
   UserBean user = new UserBean();
   user.setUsername(request.getParameter("username"));
   user.setPassword(request.getParameter("password"));

   user = UserDAO.login(user);

   if(user.isValid()){
    HttpSession session = request.getSession();
    session.setAttribute("currentSessionUser", user);
    response.sendRedirect("userLogged.jsp");
   } else {
    response.sendRedirect("invalidLogin.jsp");
   }
  } catch (Exception e){
   e.printStackTrace();
  }
 }
}

UserDAO.java ("service" class)

//snipped imports and such

public class UserDAO {

    static Connection currConn = null;
    static ResultSet rs = null;

    public static UserBean login(UserBean userBean) {
        Statement stmt = null;

        String username = userBean.getUsername();
        String password = userBean.getPassword();

        String searchQuery = "SELECT * FROM pilots x WHERE x.email = '" + username + "' AND x.password = '" + password + "'";

        System.out.println("Your user name is " + username);
        System.out.println("Your password is " + password);
        System.out.println("Query: " + searchQuery);

        try {
            currConn = ConnectionManager.getConnection();
            stmt = currConn.createStatement();
            rs = stmt.executeQuery(searchQuery);
            boolean more = rs.next();

            if (!more) {
                System.out.println("Sorry, you are not a registered user! Please sign up first");
                userBean.setValid(false);
            } else {
                String firstName = rs.getString("FIRST_NAME");
                String lastName = rs.getString("LAST_NAME");

                System.out.println("Welcome " + firstName);

                userBean.setFirstName(firstName);
                userBean.setLastName(lastName);
                userBean.setValid(true);
            }
        } catch (Exception ex) {
            System.out.println("Log In failed: An Exception has occurred! " + ex);
            ex.printStackTrace();
        } finally {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(currConn != null){
                try {
                    currConn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        return userBean;
    }
}

UserBean.java (model, a classic POJO/bean used as a DTO)

//...
public class UserBean {
 private String username;
 private String password;
 private String firstName;
 private String lastName;
 private boolean valid;

 public String getUsername() {
  return username;
 }

 public void setUsername(String username) {
  this.username = username;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public boolean isValid() {
  return valid;
 }

 public void setValid(boolean valid) {
  this.valid = valid;
 }
}

userLogged.jsp (exitpoint - view) --never mind the div elements-

<%@ page language="java" contentType="text/html; charset=windows-1250" pageEncoding="windows-1250"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html>
<head>
 <link rel="stylesheet" type="text/css" href="mystyle.css" />
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Successful login!</title>
</head>
<body>
 <div id="page">
  <div id="content_container">
   <div id="content">
   <jsp:useBean id="currentSessionUser" class="examplePackage.UserBean" scope="application">
    Welcome, <jsp:getProperty name="currentSessionUser" property="username"/> <br>
    ********<br>
    Test 0 -> ${param.name}<br>
    Test 1 -> ${paramValues.name[0]}<br>
    Test 2 -> ${paramValues[name[0]]}<br>
    Test 3 -> ${param["name"]}<br>
    Test 4 -> ${param.username}<br>
    Test 5 -> ${param["username"]}<br>
    Test 6 -> ${sessionScope.currentSessionUser.username}<br>  
    *******<br>
    Test 7 -> ${header.host}<br>
    Test 8 -> ${header["host"]}<br>
    Test 9 -> ${pageContext.request.method}<br>
   </jsp:useBean>
   </div>
  </div>
 </div> 
</body>
</html>

Webpage output is as follows (c/p directly from FireFox):

Welcome, USER_X
********
Test 0 ->
Test 1 ->
Test 2 ->
Test 3 ->
Test 4 ->
Test 5 ->
Test 6 -> USER_X
*******
Test 7 -> localhost:8080
Test 8 -> localhost:8080
Test 9 -> GET

1) My first question is regarding the scope - which scope is actually applicable?? If you checkout userLogged.jsp, lines 13 and 22 (L13 and L22), you'll see my dilemma - if I use any other scope than "application" in L13, L14 returns null value. On the other hand, should I use applicationScope on L22, it returns null (as it darn well should, since I am setting a SESSION attribute, not a context attribute!). So, the question is - why should I use application scope on L13 anyway?? I'd expect nothing other than session scope, as can be seen from my controller.

2) The other question is regarding EL - why can't I fetch request parameters in Tests 0-5? Other stuff works fine (as can be seen from output), but I can't understand how to make these request parameters printed out as I inteded (via request EL implicit objects).

3) I am also curious as to why this won't work if I were to use it (L24 of userLogged.jsp, change attribute to property="*")?

Welcome, <jsp:getProperty name="currentSessionUser" property="*"/>

It returns null, and I've matched my domain object (UserBean) properties according to JavaBeans spec. I'd expect it would return ALL userBean properties that are matchable to input type field from LoginPage.jsp and are of correct type to use the feature (must be String or primitive).

Thank you very much in advance

With regards EK

A: 

If you use jsp:useBean with the class attribute, a new bean will be instantiated and put in the requested scope. To reuse a bean taht is already available in some scope you would have to use the type attribute and set scope to "session" for example. The relationships between the different attributes are described at http://java.sun.com/products/jsp/tags/11/syntaxref11.fm14.html.

Jörn Horstmann
Thank you, I believe I understand this, but could you please try to answer specifically each point I had made? I don't quite follow you on what you wanted to say.
Quantum
As BalusC noted, the jsp:useBean isn't actually needed in your code. I think he already answered all parts of your question.
Jörn Horstmann
+1  A: 

You do not need jsp:useBean or jsp:getProperty. Get rid of them. You're already using servlets and you have already put the logged in user in the session scope with the key currentSessionUser in this line:

session.setAttribute("currentSessionUser", user);

All you need to do to display the username is the following:

<p>Welcome, ${currentSessionUser.username}</p>

To prevent XSS, use JSTL c:out:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome, <c:out value="${currentSessionUser.username}" /></p>

You definitely don't want to put it in the application scope. It'll be applied on all website visitors.


As to your request parameter question: you're firing a redirect using response.sendRedirect(). This will basically instruct the webbrowser to create a brand new request on the given URL. You didn't pass any parameters along it, so it will indeed not be available in the redirected request. It is all working as expected. If you want to have the original request parameters still available in the result page, then you should either forward the request using RequestDispatcher#forward()

request.getRequestDispatcher("page.jsp").forward(request.response);

or pass the parameters along the redirect

response.sendRedirect("page.jsp?param1=" + URLEncoder.encode(param1, "UTF-8"));

By the way, there is a major problem in your DAO code: it is not threadsafe. The connection and resultset are been declared static. It is also prone to resource leaks, the closing isn't been taken place in finally.


See also:


Update as per the comments:

When you reference an object in EL context using ${key}, it will under the hoods use JspContext#findAttribute() to locate the associated value in respectively the page, request, session and application scopes and return the first non-null value.

As to the jsp:useBean, you're basically defining a new bean in the application scope instead of referencing the existing bean in the session scope. If you reference it explicitly in the application scope as ${applicationScope.currentSessionUser} you'll see that it doesn't return the same as you've set in the session scope in the servlet. You need to replace scope="application" by scope="session".

As to the property="*", this only works when you forwards the request as answered before. Those will namely be set from request parameters.

And no, finally is certainly not an anti-pattern. It's however one of the most misunderstood/undervalued keywords among beginners. The finally block doesn't make it threadsafe. It prevents resource leaking. Removing static and declaring the resources in method local block will make it threadsafe. Regarding the DAO pattern, you may find this article useful.

BalusC
Thanks for replying and for links.1) I figured I didn't need jsp:x, but was interested academically to see how they worked (I am preparing for SCWCD). So far, I don't understand how can something that's been put in session scope be also available in CONTEXT scope....I (mis?)understood it was impossible? It certainly felt **wrong** to have currentSessionUser in context, that's why I was suprised to see that behave as it does.2) Excellent, thanks, I'll try that ASAP....it all makes sense now that you're saying it.3) Regarding `property="*"`, do you have any additional thoughs on that?
Quantum
Final point - regarding threadsafety: I was actually somewhat aware of that but wasn't sure how to get about it. After sifting through some sites, I was under the impression `finally` was actually a bit of Java anti-pattern and should be avoided if possible. Do you have an alternative suggestion here?
Quantum
1. I don't know if I expressed it clearly, but regarding `jsp:useBean` - I actually did so (replacing application scope with session scope) and was suprised to see null being returned, hence my question (you can see that USER_X appears in both session and application scope and I don't understand why). 2. I also added a `finally` block, I believe this should make it threadsafe? Do you have perhaps a better way of solving this, I really dislike static references and somehow feel there's a better way to do this.
Quantum
Check the answer update. As to the `jsp:useBean` problem: either you're not in the same session, or you're still doing it wrong, or you're not running the code you think you're running. After all, that thing is completely superfluous in this particular case.
BalusC
Thank you very much for your effort - I'll fiddle with this a bit and certainly be back with new questions :)
Quantum
You're welcome and good luck with SCWCD!
BalusC