// Copyright MageLang Institute; Version $Id: //depot/main/src/edu/modules/Servlets/magercises/FormPostingAndProcessing/solution/FormProcessingServlet.java#5 $ import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; /** * FormProcessingServlet * * This servlet will accept data sent from the browser back * to the server via an HTTP POST method call. This servlet * uses two data files: * * structurefile: The name of a file that contains data structure information * * datafile: The name of a file that contains the persistent form of the data. * * Because this servlet is used in a Magercise, we will send error messages * to the browser. Normally this is not a good idea as the browser user should * know nothing about the workings of a servlet. * * The format of the structure file is: * |||| * * name: Name of the column of data * datatype: Type of the data in the column (use only text for now) * length: Maximum number of characters in this column of data * * The format for the data file is: * |||... * * Each piece of data is stored in a file as a string. For this reason * it is best to deal with text fields. A real version of this would * work against a database, reading the database structure from the * JDBC metadata. It would also handle datatype conversions from the * actual data type to text (which is required for display on the HTML form) */ public class FormProcessingServlet extends HttpServlet implements SingleThreadModel { private static final int PIXELS_PER_CHAR = 10; public void doPost ( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { String paramStructureFile[]; String paramDataFile[]; String inputLine = ""; Vector columns = new Vector(20); ColumnInfo colInfo; // Used to read in the structure of the data // Essentially the "data dictionary" InputStream isStructure = null; InputStreamReader isrStructure = null; BufferedReader brStructure = null; int indexCol; int indexRow; int lengthCol; String title; StringTokenizer stData; // Set the Output Stream to HTML res.setContentType("text/html"); // Get a handle to the Writer going back to the client PrintWriter out = res.getWriter(); // Get a handle to the Reader coming from the client ServletInputStream in = req.getInputStream(); /** The goal of this Magercise is to read in the information * sent to this servlet from the form POST operation. * * For the first part of the exercise, send back the data * that was received, this time in what will look like a * non-editable table. * * For the second part of the exercise, save the data back * in the data file. * */ // To use the parsePostData method in HttpUtils, you // first must determine the length of the incoming content // To get this, call the getContentLength method // Use the Utility class HttpUtils to parse the information // sent from the client into a Hashtable named data // Get the name of the file that contains the structure // information. The name of the parameter sent from // the client is "structurefile". Store this information // into the variable paramStructureFile // Get the name of the file that will store the form data // The name of the parameter sent form the client // is "datafile". Store this information into the variable // paramDataFile // Validate that this is "good" data if (null == paramDataFile) { sendError(out, "Missing parameter: datafile"); return; } if (null == paramStructureFile) { sendError(out, "Missing parameter: structurefile"); return; } // Open the structure file capture the structure of the HTML Form's layout // We will use this information to parse the incoming data and also to // send it back out again. try { ServletContext context = getServletContext(); isStructure = context.getResourceAsStream(paramStructureFile[0]); isrStructure = new InputStreamReader(isStructure); brStructure = new BufferedReader(isrStructure); while ((inputLine = brStructure.readLine()) != null) { colInfo = new ColumnInfo(inputLine); if (null != colInfo) { columns.addElement(colInfo); } } } catch (Exception e) { sendError(out, "Could not open and process the file " + paramStructureFile[0] + " Got error " + e ); return; } finally { if (!(null == brStructure)) { brStructure.close(); } } // Use the structure information from columns to read in the // form's POST information. // This loop will go through each of the columns, get // the ColumnInfo and use that to collect that column's // data from the Hashtable "data" String rowValues[]; for (indexCol = 0; indexCol < columns.size(); indexCol++) { // Retrieve the ColumnInfo object for this column // Retrieve the array of strings from the Hashtable data // that corresponds to the name (hint: use getName) // of the column of interest. Place the information // into a variable named rowValues // Create a loop using indexRow and loop over length // of rowValues. Use setNextData on the ColumnInfo // object to capture the information } // Now we generate the HTML form // This code is complete, you do not need // to modify this. out.println(""); out.println("Data Display Form"); out.println(""); out.println(""); out.println(""); // Output the headers for the display table for (indexCol = 0; indexCol < columns.size(); indexCol++) { colInfo = ((ColumnInfo)columns.elementAt(indexCol)); lengthCol = colInfo.getLength(); title = colInfo.getName(); if (lengthCol < title.length()) { lengthCol = title.length(); } out.println(""); } out.println(""); // Now display the data from the POST method int numberOfRows = ((ColumnInfo)columns.elementAt(0)).getNumberOfRows(); for (indexRow = 0; indexRow < numberOfRows; indexRow++) { out.println( "" ); for (indexCol=0; indexCol < columns.size(); indexCol++) { colInfo = ((ColumnInfo)columns.elementAt(indexCol)); out.println(""); } out.println(""); } out.println("
"); out.println(colInfo.getName()); out.println("
"); out.println("" + colInfo.getData(indexRow)); out.println("
"); out.println(""); out.println(""); // To complete this Magercise, write code that writes the information // back out to the disk file. // // No solution is provided for this part. A hint is to mirror the // code in the loop above except write the information to an opened // file. // // If this system is used by multiple users at the same time there // is the general "DBMS" problem of not overwriting someone else's // updates. // // This is not an easy problem to solve because HTTP does not support // session state tracking. It is not that easy to figure out if it is // OK to save this data to disk. // // A suggestion is to use a date/time stamp. To use this, modify the // FormDisplayServlet to include an additional hidden field that contains // the date and time that the information was retrieved from the disk. // Then check the last updated date/time information on the data file // before opening it for update. If the disk file was updated after the // date time of the data sent from the client on this POST, then you // know that someone else has updated the information. // // If you find this is the case, there are several different options. // } public String getServletInfo() { return "A servlet that accepts a FORM POST from a browser"; } // Routine to send error message back to the browser // in the form of an HTML page. private void sendError(PrintWriter out, String message) throws IOException { out.println(""); out.println("Data Editing Form"); out.println(""); out.println("

Error in FormDisplayServlet

"); out.println("

"); out.println(message); out.println("

"); out.println(""); out.println(""); } }