Today I’m gonna make sure the users who created an account using my functionality described in the previous blog can actually log on and that a http session is created. This session will remain valid until the user signs out or if the user closes the browser.
For that I create a new html page. This page should contain a few things.
If a user is not signed in:
- A sign in link
- A text stating that no user in signed in

If a user is signed in:
- A sign out link
- The full name of the user

At the sign in page the user can enter his e-mail address and password. If the password is correct they will be automatically redirected to the initial page.

If the username/password combination is not correct, the user must be redirected to the “wrong password” page.

To do all this, I make use of the jQuery JavaScript library. The downloaded jquery-1.4.1.js file I placed in the /war/js folder in the Eclipse project.
To enable sessions in GAE the appengine-web.xml needs to be adjusted, the following needs to added.
<sessions-enabled>true</sessions-enabled>
Checking for sign in users
First I have to create a servlet to check if there is a session and if it contains a valid user object in the user attribute. The result of this is returned in xml. The browser will process this information with jQuery.
public class GetUserServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession(true);
PrintWriter out = resp.getWriter();
resp.setContentType("text/xml");
User user = (User) session.getAttribute("user");
if ( user!=null) {
out.println("" + user.getFullName() + "true");
} else {
out.println("false");
}
out.flush();
out.close();
}
}
The body for the session_example.html file is very simple.
<body>
<form action="/signin" method="post">
<p>Email: <input name="email"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="hidden" name="passwordOK" value="/session_example.html"></p>
<p><input type="hidden" name="passwordNOK" value="/password_error.html"></p>
<p><input type="submit" value="Sign in"></p>
</form>
</body>
To make sure that the div with the userfullname id contains the correct value (provided by the servlet in the xml tag user) a piece of jQuery JavaScript is required in the session_example.html file.
$(document).ready(function() {
$.ajax({
type: "POST",
url: 'checkuser',
success: function(xml) {
authenticated = $("authenticated", xml).text();
if (authenticated == "true") {
$("#userfullname").html($("name", xml).text());
$('#signin').hide();
}else{
$("#userfullname").html("No user signed in!");
$('#signout').hide();
}
}
});
});
When the html page loads, JavaScript executes a jQuery ajax post to the servlet mapped at checkuser, if the post was successful, the returned xml is parsed.
If the authenticated value is equal to true, the div with the id userfullname is filled the value of the user attribute from the xml and the sign in link is made hidden.
If authenticated not is true, the userfullname is filled with a fixed value “No user signed in!” and the signout link is made hidden.
This all takes care of checking is a user is signed in. Of course the user also needs to sign in.
Signing in users.
When a user clicks the sign link, the signin.html file opened.
<body>
<form action="/signin" method="post">
<p>Email: <input name="email"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="hidden" name="passwordOK" value="/session_example.html"></p>
<p><input type="hidden" name="passwordNOK" value="/password_error.html"></p>
<p><input type="submit" value="Sign in"></p>
</form>
</body>
If the “Sign in” button is pressed, a post is done to the servlet mapped to signin, besides the email and password also two hidden parameters are send. These contain the urls where the servlet should redirect to if the password is correct or incorrect.
The signin servlet processes the post.
public class SingInServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String emailParam = req.getParameter("email");
String passwordParam = req.getParameter("password");
String passwordOKredirectParam = req.getParameter("passwordOK");
String passwordNOKredirectParam = req.getParameter("passwordNOK");
HttpSession session = req.getSession(true);
User user = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query query = pm.newQuery(User.class);
query.setFilter("email == emailParam");
query.declareParameters("String emailParam");
try {
@SuppressWarnings("unchecked")
List users = (List) query.execute(emailParam);
for (User resultuser : users) {
user = resultuser;
break;
}
if (user!=null){
if (user.authenticate(passwordParam)){
session.setAttribute(session.getId(), user);
resp.sendRedirect(passwordOKredirectParam);
} else{
resp.sendRedirect(passwordNOKredirectParam);
}
} else {
resp.sendRedirect(passwordNOKredirectParam);
}
}
finally {
query.closeAll();
}
}
finally {
pm.close();
}
}
}
The servlet does a few things:
- Read all the parameters
- Creates a new session, if not one already exists
- Starts a jdo query to the datastore, based on the provided email address
- If the user can be authenticated, the user object is stored as a session attribute.
- And finally the user is redirected to the session_example.html or password_error.html page.
Signing out
Almost everything is done, signing out is the only thing left. And just for fun, I’m doing that a little different.
<div id ="signout"><a href="signout">Sign Out</a></div>
If a user clicks the “Sign Out” link, the signout link should be opened, but with some jQuery I will override the click function.
<script>
$(document).ready(function() {
$("#signout").click(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: 'signout',
success: function(data) {
window.location.href = "/session_example.html";
}
});
});
});
</script>
When a user now clicks the sign out link, a post is done to the signout servlet, and after that the user is redirected to the same page, causing the page to reload and detect that the user has logged out.
The default action (going to the signout link is disabled), making sure that that action is not executed.
The sign out servlet is pretty straightforward, it checks if a session exists and if it does, the session is invalidated.
public class SignOutServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession(false);
if (session!=null){
session.invalidate();
}
}
}
Aditional
While testing online I found out that I missed a thing in my previous blog. The logging at the appengine site was showing errors like
java.lang.RuntimeException: java.io.NotSerializableException:
jvdkamp.example.userexample.domain.User
I fixed that by adding “implements java.io.Serializable” to the user class.
Hmmm, it seems like I don’t complete have it yet. Locally it is running fine, but online at appspot.com, the performance is bad.
I’m receiving all kind of the following errors:
Uncaught exception from servlet com.google.appengine.api.datastore.DatastoreTimeoutException: Unknown at com.google.appengine.api.datastore.Datastore
UPDATE feb 11 2010 : Apparently Google did some changes in de SDK version 1.3.1, that will make sure that if a timeout occurs the transaction is retried automatically.
Next steps
This sign in functionality is nice, it does the trick, but is not really nice looking and is missing some functionality. In the near future I will be adding some functionality:
- Taking a look at the performance issue
- Some layout, perhaps following Web Form Design Patterns: Sign-Up Forms
- Pop up sign in e.g. like twitter currently uses.
- Signing in using https
- Using an OpenID to log on
- Add forget password/generate new password functionality
- Adding cookies, so that if a user closes the browser and comes back later, the site still knows who he is.