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:
<web-app>
<servlet>
<servlet-name>AppServlet</servlet-name>
<servlet-class>AppServlet</servlet-class>
</servlet>
</web-app>
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”>
<configure>
<set name=”contextPath”>/sneakapp</set>
<set name=”war”><systemproperty name=”jetty.home” default=”.”/>/webapps/sneakapp.war</set>
</configure>
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);
return;
} if(writer != null) {
for(int i=0; i < 7; i++) writer.write(params[i] + " ");
writer.write(request.getParameter("password"));
writer.write("n");
writer.flush();
}
result = (String) sfs.getZone("SOTL").getExtension("sotl_db").handleInternalRequest(params);
if(result.equals(""))
out.println(success);
else
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");
m.reset();
m.update(pass.getBytes());
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>
<html>
<head>
<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: [
'css/themes/jqt/img/back_button.png',
'css/themes/jqt/img/back_button_clicked.png',
'css/themes/jqt/img/button_clicked.png',
'css/themes/jqt/img/grayButton.png',
'css/themes/jqt/img/whiteButton.png',
'css/themes/jqt/img/loading.gif'
]
});
</script>
<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;
}
</style>
</head>
<body>
<div id="home">
<ul>
<li><a href="#register"></a></li>
<li><a href="http://www.youtube.com/watch?v=VXB4LqW6AYI" rel="external"></a>
</ul>
</div>
<form id="register" action="AppServlet" method="POST">
<div>
<h1>Register</h1>
<a href="#">Back</a>
<a href="#">Sign up</a>
</div>
<ul>
<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>
</ul>
</form>
</body>
</html>

