package webIM; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; /** * Title: Monitor * Description: This servlet is first invoked when the user selects the link of an * online buddy from the buddy list. It receives the buddy's name in * a cookie, and completes the initialization of the conversation. * This first invocation is via the form submitted from the static * page, talk.html. * * Afterwards, this servlet receives POST requests from the Talk * frame containing new chat text from the local user. It also receives * GET requests from the buddy's Chat servlet that have a query parameter * equal to the remote filename. Local chat submissions are written to disk * and the filename is added to the newFilesList. The filenames from * remote submissions are added to the newFilesList. The text form * is redisplayed by including talk.jsp. * Copyright: Copyright (c) 2001 * Company: UCCS Computer Science Department * @author Merlin Vincent * @version 1.0 */ public class Monitor extends HttpServlet { private static final String CONTENT_TYPE = "text/html"; private static String endl = System.getProperty("file.separator"); // A number used to order local files. Filename format: user_buddy_ext private int nextLocalFileExt = 0; /**Initialize global variables*/ public void init(ServletConfig config) throws ServletException { super.init(config); } /** * Process the HTTP Get request. This is NEVER invoked by the local user. * The initial GET for the text input form is from a static HTML page * rather than from this servlet. * * This GET is invoked when the remote user's Chat servlet has new text * that we should retrieve. This servlet is invoked with: * * * */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); ServletContext context = getServletContext(); ArrayList newFilesList = null; // Get the newChat query parameter String newFile = request.getParameter("newChat").trim(); if (newFile == null) throw new ServletException("Monitor GET: no newRemoteFile parameter"); /** * Parse out the names of the talkers so we can retrieve the global * sequence number, whose key is of the form userBuddySeqNo. * The new chat filename, e.g., "buddy_user_n". */ int endBuddy = newFile.indexOf("_"); int endUser = newFile.lastIndexOf("_"); String buddyName = newFile.substring(0, endBuddy).trim(); String userNickName = newFile.substring(endBuddy + 1, endUser).trim(); String contextKey = userNickName + buddyName; /** * If the buddy submits text before the local user does, the newFilesList * will not exist - create it, and capture the selected buddy's name * and the sequence number that tracks all received/submitted messages. */ newFilesList = (ArrayList) context.getAttribute( contextKey+"NewChat"); if (newFilesList == null) { newFilesList = new ArrayList(); context.setAttribute( contextKey+"NewChat", newFilesList ); context.setAttribute( userNickName+"selectedBuddy", buddyName ); context.setAttribute( contextKey+"SeqNo", new Integer(0)); } // Capture the buddy's filename and bump the sequence number. synchronized (newFilesList) { newFilesList.add( newFile ); Integer seqNo = (Integer) context.getAttribute( contextKey+"SeqNo" ); int sequenceNumber = seqNo.intValue(); context.setAttribute( contextKey+"SeqNo", new Integer(sequenceNumber + 1)); } // Send an error response so the will fail quickly. response.setStatus( HttpServletResponse.SC_NOT_FOUND ); } /**Process the HTTP Post request*/ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String buddyName = null; String userName = null; String nickName = null; int sequenceNumber = 0; HttpSession session = request.getSession(false); ServletContext context = getServletContext(); ArrayList newFilesList = null; //Get the submitted text - if none, just redisplay the text input form if (request.getContentLength() == 0) { RequestDispatcher dispatcher = getServletContext().getRequestDispatcher( "/talk.jsp" ); dispatcher.include(request, response); return; } // Retrieve the existing session and its variables. if (session == null) throw new ServletException("Monitor POST: no HttpSession"); userName = (String) session.getAttribute("username"); if (userName == null) throw new ServletException("Monitor POST: no username in session"); nickName = (String) session.getAttribute("nickname"); if (userName == null) throw new ServletException("Monitor POST: no nickname in session"); buddyName = (String) context.getAttribute(nickName+"selectedBuddy"); if (buddyName == null) throw new ServletException("Monitor POST: no buddy name in session"); /** * If this is the first call, get the selected buddy's name, init the * sequence number that tracks all received/submitted messages, and * create the newFilesList to hold the messages. */ if (buddyName.equals("none")) { Cookie cookie; Cookie[] cookies = request.getCookies(); if (cookies == null) throw new ServletException("Monitor POST: no cookies available"); for(int i=0; i < cookies.length; i++) { cookie = cookies[i]; if (cookie.getName().equals("selectedBuddy")) { buddyName = cookie.getValue().trim(); break; } } if (buddyName == null) throw new ServletException("Monitor POST: no selectedBuddy cookie"); context.setAttribute(nickName+"selectedBuddy", buddyName); context.setAttribute( nickName+buddyName+"SeqNo", new Integer(0)); newFilesList = new ArrayList(); context.setAttribute( nickName+buddyName+"NewChat", newFilesList ); } /** * Build the local filename for the submitted text. This name always * includes the full path, so it starts with a slash. The filenames for * remote submissions start with a character, and can be differentiated. */ String filename = new String( nickName + "_" + buddyName + "_" + ( nextLocalFileExt++ )); String path = new String("/users/server/students/" + userName +"/public_html/webIM/"); // Get the submitted text and write it to the disk file String input = request.getParameter("inputText"); writeFile((path + filename), input); // Add the new file and increment the global sequence number. newFilesList = (ArrayList) context.getAttribute( nickName+buddyName+"NewChat"); if (newFilesList == null) throw new ServletException("Monitor POST: no new files list in session"); synchronized (newFilesList) { Integer seqNo = (Integer) context.getAttribute(nickName+buddyName+"SeqNo"); sequenceNumber = seqNo.intValue(); context.setAttribute( nickName+buddyName+"SeqNo", new Integer(sequenceNumber + 1)); newFilesList.add( path + filename ); } // Redisplay the text input form. RequestDispatcher dispatcher = getServletContext().getRequestDispatcher( "/talk.jsp" ); dispatcher.include(request, response); } /** * This method writes the text submitted by the user to a disk file * named /users/server/students/user/public_html/webIM/user_buddy_ * where is the message sequence number. */ private void writeFile (String filename, String inputText) throws ServletException { File f = null; FileOutputStream fos = null; try { f = new File(filename); f.createNewFile(); if (f.exists() && f.isFile() && f.canWrite()) { fos = new FileOutputStream( f ); byte[] txtBytes = inputText.getBytes(); fos.write( txtBytes ); fos.close(); fos = null; } } catch (IOException e) { throw new ServletException("Monitor writeFile: unable to write file "+ filename); } finally { if (fos != null) { try {fos.close();} catch (IOException ioe){} fos = null; } f = null; } } /**Clean up resources*/ public void destroy() { } }