JQTouch mobile app integration with SmartFoxServer

In the previous articles on  http://surgeworksmobile.com/cross-platform/jqtouch-mobile-app-for-user-registration-tutorial, I focused on the JQTouch side of things. I’d like to mention the ingredients to make the app work with SmartFoxServer since that can be tricky.

I built both grails and jython web services to serve as the back end interface for this application. Unfortunately, both these implementations would not work with SFS, so I made a very simple JSP servlet to handle registration requests.

First, the structure of the app. Do not provide any jar files. They need to be provided by SFS:

in WEB-INF/web.xml:

sneakapp.xml, in the top directory, we document where the servlet will appear in the web site’s hierarchy.

< ?xml version=”1.0″  encoding=”ISO-8859-1″?>
< !DOCTYPE Configure PUBLIC “-//Mort Bay Consulting//DTD Configure//EN” “http://jetty.mortbay.org/configure.dtd”>
<set name=”contextPath”>/sneakapp</set>
<set name=”war”><systemproperty name=”jetty.home” default=”.”/>/webapps/sneakapp.war</set>

in images/ are the .png files refered by index.html.

css/ contains the jqtouch css support files.

js/jqtouch contains the jqtouch javascript  files.

To deploy, the app, build a war, place it, and restart SFS:

javac WEB-INF/classes/AppServlet.java
jar cvf /opt/SFS_PRO_1.6.6/Server/webserver/webapps/sneakapp.war .
/etc/init.d/sfs stop ; /etc/init.d/sfs start

Finally, the servlet code in WEB-INF/classes/AppServlet.java. A few points to note.

  • Output is formatted for use by JQTouch, with a place in the warning string to place error messages
  • The SFS hook is handled in handleInternalRequest. This call accepts a list of strings and returns a string
  • The servlet performs basic validation; all validation happens at the server
import java.security.*;
import java.math.*;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.json.*;

import it.gotoandplay.smartfoxserver.*;

public class AppServlet extends HttpServlet {
  private static SmartFoxServer sfs;
  private static String success;
  private static String failure;
  private static String warning;
  private static BufferedWriter writer = null;

  public void init(ServletConfig config) throws ServletException {
    sfs = SmartFoxServer.getInstance();
    success = "<div id="confirm"> <div class="toolbar"> <h1>Thank you</h1> <a href="#home" class="back">Home</a> </div> <center> Thank you for signing up!  <p>You will receive an email soon with instructions on how to activate your account.  <p>Please also check your Spam folder! </center> </div>";
    failure = "<div id="fail"> <div class="toolbar"> <a href="#register" class="back">Try again</a> </div> <center> <div class="message">This username or email are in use already. Please try again and complete all required fields.</div> </center> </div>";
    warning = "<div id="fail"> <div class="toolbar"> <a href="#register" class="back">Try again</a> </div> <center> <div class="message">%s Please try again.</div> </center> </div>";

    try {
      writer = new BufferedWriter(new FileWriter("/var/www/out.txt",true));
    } catch(Exception e) {}

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

    String hash = "";
    String emailhash = "";
    String key = "";
    String result = "";

    try {
      hash = mymd5(request.getParameter("password"));
      emailhash = mymd5(request.getParameter("email"));
      key = mymd5("token" + Math.random());
    } catch(Exception e) {}

    String params[] = new String[7];
    params[0] = request.getParameter("username");
    params[1] = hash;
    params[2] = request.getParameter("first_name");
    params[3] = request.getParameter("last_name");
    params[4] = request.getParameter("email");
    params[5] = emailhash;
    params[6] = key; 

    PrintWriter out = response.getWriter();
    try {
      String msg = "";
      msg += verify(request, "first_name", "First name");
      msg += verify(request, "last_name", "Last name");
      msg += verify(request, "email", "email");
      msg += verify(request, "username", "Username");
      msg += verify(request, "password", "password");
      if(!msg.equals("")) {
        out.format(warning, msg);
      } if(writer != null) {
        for(int i=0; i < 7; i++) writer.write(params[i] + " ");
      result = (String) sfs.getZone("SOTL").getExtension("sotl_db").handleInternalRequest(params);
        out.format(warning, result);
    } catch(Exception e) {
      out.format(warning, e.toString());

  public String verify(HttpServletRequest request, String parameter, String name) {
    if(request.getParameter(parameter) == null || request.getParameter(parameter).equals("")) {
      return name + " is required.";
    return "";

  public static String mymd5(String pass) throws NoSuchAlgorithmException {
    MessageDigest m = MessageDigest.getInstance("MD5");
    byte[] digest = m.digest();
    BigInteger bigInt = new BigInteger(1,digest);
    String hashtext = bigInt.toString(16);
    // Now we need to zero pad it if you actually want the full 32 chars.
    while(hashtext.length() < 32 ){
      hashtext = "0"+hashtext;
    return hashtext;


Again, the index.html from the root of the java project ties everything together, pulls in JQTouch, and connects the form to the servlet:

<!doctype html>
 <meta charset="UTF-8" />
 <title>Sneak on the Lot</title>
 <style type="text/css" media="screen">@import "js/jqtouch/jqtouch.min.css";</style>
 <style type="text/css" media="screen">@import "css/themes/jqt/theme.min.css";</style>
 <script src="js/jqtouch/jquery.1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="js/jqtouch/jqtouch.min.js" type="application/x-javascript" charset="utf-8"></script>

 <script type="text/javascript" charset="utf-8">
 var jQT = new $.jQTouch({
 icon: 'images/icon.png',
 addGlossToIcon: false,
 startupScreen: 'images/splash.jpg',
 statusBar: 'black',
 preloadImages: [
 <style type="text/css" media="screen">
 #home {
 background-image: url(images/main.jpg);
 background-repeat: no-repeat;
 a.splashlink {
 position: absolute;
 display: block;
 padding: none;
 margin: none;
 text-shadow: none;
 background-color: transparent;
 border-bottom: none;
 border-top: none;
 .register {
 width: 140px;
 height: 40px;
 top: 156px;
 left: 89px;
 .video {
 width: 72px;
 height: 63px;
 top: 284px;
 left: 17px;
 ul.nostyle {
 -webkit-background-clip: none;
 background-image: none;
 background-color: none;
 color: none;
 border-bottom-width: 0;
 border-left-width: 0;
 border-right-width: 0;
 border-top-width: 0;
 li.nostyle {
 -webkit-background-clip: none;
 background-image: none;
 background-color: none;
 color: none;
 border-bottom-width: 0;
 border-left-width: 0;
 border-right-width: 0;
 border-top-width: 0;
 <div id="home">
 <li><a href="#register"></a></li>
 <li><a href="http://www.youtube.com/watch?v=VXB4LqW6AYI" rel="external"></a>
 <form id="register" action="AppServlet" method="POST">
 <a href="#">Back</a>
 <a href="#">Sign up</a>
 <li><input type="text" name="first_name" placeholder="First Name" id="some_name" /></li>
 <li><input type="text" name="last_name" placeholder="Last Name" id="some_name" /></li>
 <li><input type="text" name="email" placeholder="Email" id="some_name" autocapitalize=off /></li
 <li><input type="text" name="username" placeholder="Username by which you'll be known" id="some_
name" autocapitalize=off /></li>
 <li><input type="password" name="password" placeholder="password" id="some_name" /></li>