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