Computer Science 15-100, Fall 2008
Notes: Bonus Lecture on Writing Servlets
See the general notes on bonus lectures.
Note: In this bonus lecture, in order to place our servlets online, we created free accounts from "eatj". An eatj account is a real account from a real vendor on the real web. Meaning: while you can and should experiment with it, be prudent with it. Using that account to spam the world or for denial-of-service attacks, for instance, would qualify as (very) imprudent. But testing your own distributed, multiplayer Tetris game (whatever that would look like…) is a GREAT way to use the site!
Steps to create and use an "eatj" account:
1) Create eatj account
2) eatj Getting Started
http://s41.eatj.com/index.jsp?url=getting_started.html
3) Modify HelloServlet
a) edit WEB-INF\src\util\HelloServlet.java
b) download Apache Tomcat (http://tomcat.apache.org/download-55.cgi)
c) copy apache-tomcat-5.5.27/common/lib/servlet-api.jar to WEB-INF\src\util
d) add that jar to your classpath and/or your IDE's libraries
e) slightly modify and compile HelloServlet.java
f) be sure your class file lives in WEB-INF\classes\util\HelloServlet.class
g) rebuild and reupload ROOT.war and restart Tomcat
4) Create MyTestServlet
a) Copy WEB-INF\src\util\HelloServlet.java to MyTestServlet.java
b) slightly modify and compile MyTestServlet.java
c) be sure your class file lives in WEB-INF\classes\util\MyTestServlet.class
d) edit WEB-INF\web.xml
1) Add servlet and servlet-mapping entries for MYTestServlet
that are copied-and-edited from HelloServlet entries
e) rebuild and reupload ROOT.war and restart Tomcat
f) Run your servlet as such: (replace "dkosbie.s155" as appropriate)
http://dkosbie.s155.eatj.com/servlet/util.MyTestServlet
5) Add parameters to MyTestServlet
a) Add this code to MyTestServlet.java's processRequest:
out.println("<hr>");
out.println("Here are the parameters:");
out.println("<br>");
java.util.Enumeration parameters = request.getParameterNames();
while (parameters.hasMoreElements()) {
String parameter = (String) parameters.nextElement();
String value = request.getParameter(parameter);
out.println(parameter + " : " + value);
out.println("<br>");
}
out.println("<hr>");
b) rebuild and reupload ROOT.war and restart Tomcat
c) Run your servlet as such: (replace "dkosbie.s155" as appropriate)
http://dkosbie.s155.eatj.com/servlet/util.MyTestServlet?foo=1&bar=wahoo
Here is the code we wrote together. It has the usual disclaimers for code written by a group during a bonus lecture, with design-by-committee flaws and surely bugs here and there, and with a near contempt for good style. But here it is, and it works more or less.
// MyTestServlet.java
package util;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyTestServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
String msg = "err: unknown error";
try {
String cmd = request.getParameter("cmd");
String userId = request.getParameter("userId");
msg = (new MySimpleGameServer(cmd, userId)).getResponse();
}
catch (Exception e) {
msg = "err: " + e.getMessage();
}
PrintWriter out = response.getWriter();
out.println(msg);
out.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { processRequest(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { processRequest(request, response); }
public String getServletInfo() { return "MyTestServlet"; }
public static void main(String[] args) {
MyGameTester.playOnline();
}
}
class MyGameTester {
public static void playStandalone() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter userId: ");
String userId = scanner.nextLine();
System.out.print("Enter cmd: ");
String cmd = scanner.nextLine();
String msg;
msg = (new MySimpleGameServer(cmd, userId)).getResponse();
System.out.println(msg);
}
}
public static String login() {
return getResponseFromServer("login","");
}
public static void playOnline() {
Scanner scanner = new Scanner(System.in);
String userId = login();
System.out.println("userId = " + userId);
while (true) {
System.out.print("Enter cmd (or 'quit'): ");
String cmd = scanner.nextLine();
if (cmd.equals("quit")) break;
String msg = getResponseFromServer(cmd, userId);
System.out.println(msg);
}
String cmd = "logout";
String msg = getResponseFromServer(cmd, userId);
System.out.println(msg);
}
public static String getResponseFromServer(String cmd, String userId) {
String url = "http://dkosbie.s155.eatj.com/servlet/util.MyTestServlet";
url += "?cmd=" + cmd + "&userId=" + userId;
Scanner scanner = getUrlTextScanner(url);
return scanner.nextLine();
}
// Convenient helper method for reading from a web page (url) as plain text.
// Returns null if the page cannot be opened (or for any other error).
// On some pages, especially if they contain XML, the spaces may be elided
// (sothetextislikethis) -- in that case, try setting the second parameter
// to " " or "\n", so spaces or newlines are added after each parsed element.
// You are responsible for using this method, but not
// for writing it (neither on homeworks or tests)!
public static Scanner getUrlTextScanner(String url) { return getUrlTextScanner(url, null); }
public static Scanner getUrlTextScanner(String url, final String dataDelimiter) {
Scanner scanner = null;
try {
final StringBuffer sb = new StringBuffer();
java.io.InputStreamReader reader = new java.io.InputStreamReader(
new java.net.URL(url).openStream());
javax.swing.text.html.HTMLEditorKit.ParserCallback parser =
new javax.swing.text.html.HTMLEditorKit.ParserCallback() {
public void handleText(char[] data, int pos) {
if (data != null) {
sb.append(data);
if (dataDelimiter != null) sb.append(dataDelimiter);
}
}
public void handleSimpleTag(javax.swing.text.html.HTML.Tag tag,
javax.swing.text.MutableAttributeSet a,
int pos) {
if (tag.breaksFlow()) sb.append("\n");
}
};
new javax.swing.text.html.parser.ParserDelegator().parse(reader, parser, true);
scanner = new Scanner(sb.toString());
}
catch (Exception e) {
System.out.println("Error opening text reader for url: " + url);
return null;
}
return scanner;
}
}
class MyGameServer {
public String doCommand(String cmd, String userId) { return "ok"; }
public void deserializeData(ArrayList<String> data) { }
public void serializeData(ArrayList<String> data) { }
public void reset() { }
protected void deserializeSystemData(ArrayList<String> data) {
if (data == null) {
}
else {
// get the startIndex from the end
int index = Integer.parseInt(data.get(data.size()-1));
// now get the userIds
int userIdCount = Integer.parseInt(data.get(index++));
for (int i=0; i<userIdCount; i++)
userIds.add(data.get(index++));
}
}
protected ArrayList<String> userIds = new ArrayList<String>();
protected void serializeSystemData(ArrayList<String> data) {
int startIndex = data.size();
// serialize the user id's
data.add("" + userIds.size());
for (String userId : userIds)
data.add(userId);
// store the startIndex at the end
data.add("" + startIndex);
}
protected String response;
public MyGameServer(String cmd, String userId) {
response = "err: Unknown error";
try {
// load the data from the file
String stateFileName = getClass().getName() + ".txt";
Scanner scanner = getFileScanner(stateFileName);
ArrayList<String> serializedData = new ArrayList<String>();
if (scanner == null)
serializedData = null;
else {
while (scanner.hasNext())
serializedData.add(scanner.nextLine());
}
deserializeData(serializedData);
deserializeSystemData(serializedData);
// do the command
if (cmd == null)
throw new RuntimeException("No cmd specified");
if ((!cmd.equals("login")) && (userId == null))
throw new RuntimeException("No userId specified");
if (cmd.equals("login"))
response = doLogin();
else if (!userIds.contains(userId))
throw new RuntimeException("No such userId: " + userId);
else if (cmd.equals("logout"))
response = doLogout(userId);
else if (cmd.equals("reset")) {
reset();
response = "ok";
}
else
response = doCommand(cmd, userId);
// store the data back to the file
serializedData = new ArrayList<String>();
serializeData(serializedData);
serializeSystemData(serializedData);
PrintStream out = getFilePrintStream(stateFileName);
for (String line : serializedData)
out.println(line);
out.close();
}
catch (Exception e) {
response = "err: " + e.getMessage();
}
}
public String getResponse() { return response; }
protected static final Random random = new Random();
public String doLogin() {
Integer id = 0;
do
id = 1000 + random.nextInt(9000);
while (userIds.contains(id));
userIds.add("" + id);
return "" + id;
}
public String doLogout(String userId) {
userIds.remove(userId);
return "ok";
}
// Convenient helper method for reading from a file.
// Returns null if the file is not found (or for any other error).
// You are responsible for using this method, but not
// for writing it (neither on homeworks or tests)!
public static Scanner getFileScanner(String filename) {
Scanner scanner = null;
try { scanner = new Scanner(new java.io.File(filename)); }
catch (Exception e) {
// System.out.println("File not found");
return null;
}
return scanner;
}
// Convenient helper method for writing to a file.
// Returns null if the file cannot be opened (or for any other error).
// You are responsible for using this method, but not
// for writing it (neither on homeworks or tests)!
public static PrintStream getFilePrintStream(String filename) {
PrintStream out = null;
try { out = new PrintStream(new java.io.File(filename)); }
catch (Exception e) {
System.out.println("Error opening file " + filename);
return null;
}
return out;
}
}
// plays "Get20"
class MySimpleGameServer extends MyGameServer {
public MySimpleGameServer(String cmd, String userId) { super(cmd, userId); }
private int counter;
private int winValue;
public void reset() {
counter = 0;
winValue = 15+random.nextInt(5);
}
public void deserializeData(ArrayList<String> data) {
if (data == null)
reset();
else {
counter = Integer.parseInt(data.get(0));
winValue = Integer.parseInt(data.get(1));
}
}
public void serializeData(ArrayList<String> data) {
data.add("" + counter);
data.add("" + winValue);
}
public String doCommand(String cmd, String userId) {
if (cmd.equals("add")) {
counter++;
if (counter < winValue)
return "ok (counter = " + counter + ")";
else if (counter == winValue)
return "YOU WIN!!!";
else
return "YOU LOSE (counter = " + counter + ")";
}
else throw new RuntimeException("I can only add, not this: " + cmd);
}
}
carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem